Load libraries and public variables

# File that contains simulation output data in a HDF5 directory structure specified in "/publicVariables/createPublicVariables.Rmd"
simOutputH5 <- paste0("../../dataProcessing/simOutputH5Data/", experimentID, "_output.h5")
#allSimInputOutput <- read_tsv("../allSimInputOutput.feather")

# This folder contains raw output files from the simulations. This is needed for calculate_para_sp_mcpsr()
rawSimOutFolder <- "/team/batch_SMOTNT/experiment1_output"

Refer to Supplementary Methods for the mathematical equations of each of the following calculated metrics.

# mpsr = mean protein synthesis rates;  
calculate_gene_sp_mpsr <- function(geneID, simOutputH5){   
    # outvec has 25 elements. Each element is the mpsr (# of ribos that hop off per min for a gene) for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]

    # matrix that contains countElng info for current selected gene in mRNAconstant data
    # ps = protein synthesis
    # mpsr = mean protein synthesis rate
    ps_mRNAconstant <- h5read(simOutputH5, paste0(currentGene, "/gene_sp_countElng_perMin/mRNAconstant"))
    mpsr_mRNAconstant <- mean(ps_mRNAconstant)
    outvec <- c(outvec, mpsr_mRNAconstant)
    
    # loop through the dc/r parameter space to calculate the mean_countElng_mRNAvarying
    for(i in 2:nrow(dc.r.df)){
        ps_mRNAvarying <- h5read(simOutputH5, paste(currentGene, "gene_sp_countElng_perMin", dc.r.df$paraCombo[i], sep = "/"))
        mpsr_mRNAvarying <- mean(ps_mRNAvarying)
        outvec <- c(outvec, mpsr_mRNAvarying)
    }
    
    h5closeAll()
    return(outvec)
}
# mvps = mean of the (variance in protein synthesis among simu times) among technical replicates 
calculate_gene_sp_mvps <- function(geneID, simOutputH5){  
    # outvec has 25 elements. Each element is the mvps for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]
    
    # matrix that contains countElng info for current selected gene in mRNAconstant data
    ps_mRNAconstant <- h5read(simOutputH5, paste0(currentGene, "/gene_sp_countElng_perMin/mRNAconstant"))
    # get variance for each row(rep) and then get the mean for all reps
    mvps_mRNAconstant <- mean(apply(ps_mRNAconstant, 1, var))  
    outvec <- c(outvec, mvps_mRNAconstant)
    
    # loop through the dc/r parameter space 
    for(i in 2:nrow(dc.r.df)){ 
        # ps_mRNAvarying is a 50 X 720 matrix
        ps_mRNAvarying <- h5read(simOutputH5, paste(currentGene, "gene_sp_countElng_perMin", dc.r.df$paraCombo[i], sep = "/"))
        # get variance for each row (rech rep) and then get the mean for all technial reps
        mvps_mRNAvarying <- mean(apply(ps_mRNAvarying, 1, var, na.rm = TRUE))  
        outvec <- c(outvec, mvps_mRNAvarying)
    }
    
    h5closeAll()
    return(outvec)
}
# cvps = coefficient variation of total protein produced per minute
calculate_gene_sp_cvps <- function(geneID, simOutputH5){  
    # outvec is a vector that has 25 elements. Each element is the mvps for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]
    
    # loop through the dc/r parameter space to calculate the mean_countElng_mRNAvarying
    for(i in 1:nrow(dc.r.df)){ 
        ps <- h5read(simOutputH5, paste(currentGene, "gene_sp_countElng_perMin", dc.r.df$paraCombo[i], sep = "/"))
        mpsr <- mean(ps) # mean
        # get standard deviation for each row(rep) and then get the mean for all reps
        sdps <- mean(apply(ps, 1, sd, na.rm = TRUE))  
        # cvps = coefficient of variation of protein synthesis
        cvps <- sdps/mpsr 
        outvec <- c(outvec, cvps)
    }
    
    h5closeAll()
    return(outvec)
}
# cpsr = cellular protein synthesis rate, this function returns the cpsr for 50 technical replicate that is of the same paraCombo, it is therefore not joined into allSimInputOutput
# pid = parameter id, 1:25, 1 = mRNAconstant, 2:25 = different dc/r combos, output is a number
calculate_para_sp_cpsr <- function(pid){  
    # there are 25 para combo * 50 reps = 1250 files in this folder                              
    countElngFolder <- paste0(rawSimOutFolder, "/gene_sp_countElng_perMin/") 
    
    # N = # of tech reps, here NcountElngFiles contains 50 file contents
    if(pid == 1){
        NcountElngFiles <- list.files(countElngFolder, pattern = glob2rx(paste0("*dc_0_r_0_mRNAconstant*")))
    }else{
        NcountElngFiles <- list.files(countElngFolder, pattern = glob2rx(paste0("*", dc.r.df$paraCombo[pid], "_allGenesDecrEqualsSynrScaling*")))
    }
    
    cpsr.all.techRep <- c()
    for(ii in 1:numTechReps){ 
        # cps = cellular protein synthesis, is a vector that contains 719 numbers(720-1)
        cps = apply(read.table(file = paste0(countElngFolder, NcountElngFiles[ii]))[, 2:4840], 1, sum) # get the sum of each line in a single file
      
        # cps give a vector of 719 numbers, then you get the mean of those 719 numbers
        # cpsr = cellular protein synthesis rate
        cpsr <- mean(cps)
        cpsr.all.techRep <- c(cpsr.all.techRep, cpsr)  # this will contain 50 numbers
    }

    return(cpsr.all.techRep)
}
# mcpsr = mean cellular protein synthesis rate
# parameter id, 1:25, 1 = mRNAconstant, 2:25 = different dc/r combos, output is a number
calculate_para_sp_mcpsr <- function(pid){  
    # there are 25 para combo * 50 reps = 1250 files in this folder                  
    countElngFolder <- paste0(rawSimOutFolder, "/gene_sp_countElng_perMin/") 
    
    # N = # of tech reps, here NcountElngFiles contains 50 file contents
    if(pid == 1){
        NcountElngFiles <- list.files(countElngFolder, pattern = glob2rx(paste0("*dc_0_r_0_mRNAconstant*")))
    }else{
        NcountElngFiles <- list.files(countElngFolder, pattern = glob2rx(paste0("*", dc.r.df$paraCombo[pid], "_allGenesDecrEqualsSynrScaling*")))
    }
    
    cpsr.all.techRep <- c()
    for(ii in 1:numTechReps){
        # cps = cellular protein synthesis, is a vector that contains 720 numbers
        # get the sum of each line in a single file
        cps = apply(read.table(file = paste0(countElngFolder, NcountElngFiles[ii]))[, 2:4840], 1, sum) 
        
        # cpsr = cellular protein synthesis rate = get the mean of those 720 numbers in cps
        cpsr <- mean(cps)
        # this will contain 50 numbers, 1 for each tech rep
        cpsr.all.techRep <- c(cpsr.all.techRep, cpsr)  
    }
    # mean of the cpsr among 50 technical reps
    mcpsr <- mean(cpsr.all.techRep)
    return(mcpsr)
}
# mte = mean translation efficiency
calculate_gene_sp_mte <- function(geneID, simOutputH5){   
    # outvec has 25 elements. Each element is the mte for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes, and its initial mRNA level
    currentGene <- geneNames[geneID]
    mRNAabundanceCurrentGene <- simInputFeatures$mRNAabundance[geneID]
    
    # matrix that contains countElng info for current gene.
    # te = translation efficiency, mte = mean translation efficiency
    countElng_mRNAconstant <- h5read(simOutputH5, paste0(currentGene, "/gene_sp_countElng_perMin/mRNAconstant"))
    te_mRNAconstant <- countElng_mRNAconstant/mRNAabundanceCurrentGene
    mte_mRNAconstant <- mean(te_mRNAconstant)
    outvec <- c(outvec, mte_mRNAconstant)
    
    # loop through the dc/r parameter space
    for(i in 2:nrow(dc.r.df)){ 
        countElng_mRNAvarying <- h5read(simOutputH5, paste(currentGene, "gene_sp_countElng_perMin", dc.r.df$paraCombo[i], sep = "/"))
        mRNAcount_mRNAvarying <- h5read(simOutputH5, paste(currentGene, "gene_sp_mRNAcount_perMin", dc.r.df$paraCombo[i], sep = "/"))
        # te = translation efficiency
        te_mRNAvarying <- countElng_mRNAvarying/mRNAcount_mRNAvarying   
        # change all the "Inf"s to "Nan"s
        te_mRNAvarying[!is.finite(te_mRNAvarying)] <- NaN 
        # mte = mean translation rate averaged over time and tech reps
        mte_mRNAvarying <- mean(te_mRNAvarying, na.rm = TRUE) 
        outvec <- c(outvec, mte_mRNAvarying)
    }
    
    h5closeAll()
    return(outvec)
}
# mvte = mean of the variance in translation efficiency
calculate_gene_sp_mvte <- function(geneID, simOutputH5){     
    # outvec has 25 elements. Each element is the mvte for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes, and its initial mRNA level
    currentGene <- geneNames[geneID]
    mRNAabundanceCurrentGene <- simInputFeatures$mRNAabundance[geneID]
    
    # matrix that contains countElng info for current selected gene
    countElng_mRNAconstant <- h5read(simOutputH5, paste0(currentGene, "/gene_sp_countElng_perMin/mRNAconstant"))
    te_mRNAconstant <- countElng_mRNAconstant/mRNAabundanceCurrentGene
    # get variance for each row(rep) and then get the mean for all reps
    mvte_mRNAconstant <- mean(apply(te_mRNAconstant, 1, var, na.rm = TRUE))  
    outvec <- c(outvec, mvte_mRNAconstant)
    
    # loop through the dc/r parameter space
    for(i in 2:nrow(dc.r.df)){  
        countElng_mRNAvarying <- h5read(simOutputH5, paste(currentGene, "gene_sp_countElng_perMin", dc.r.df$paraCombo[i], sep = "/"))
        mRNAcount_mRNAvarying <- h5read(simOutputH5, paste(currentGene, "gene_sp_mRNAcount_perMin", dc.r.df$paraCombo[i], sep = "/"))
        # te = translation rate
        te_mRNAvarying <- countElng_mRNAvarying/mRNAcount_mRNAvarying   
        # change all the "Inf"s to "Nan"s
        te_mRNAvarying[!is.finite(te_mRNAvarying)] <- NaN 
        # get var for each row(rep) and then get the mean for all reps
        mvte_mRNAvarying <- mean(apply(te_mRNAvarying, 1, var, na.rm = TRUE))  
        outvec <- c(outvec, mvte_mRNAvarying)
    }
    
    h5closeAll()
    return(outvec)
}
# mmc = mean mRNA count
calculate_gene_sp_mmc <- function(geneID, simOutputH5){   
    # outvec has 25 elements. Each element is the mmc for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes,  and its initial mRNA level
    currentGene <- geneNames[geneID]
    mRNAabundanceCurrentGene <- simInputFeatures$mRNAabundance[geneID]
    outvec <- c(outvec, mRNAabundanceCurrentGene)
    
    # loop through the dc/r parameter space
    for(i in 2:nrow(dc.r.df)){  
        mRNAcount_mRNAvarying <- h5read(simOutputH5, paste(currentGene, "gene_sp_mRNAcount_perMin", dc.r.df$paraCombo[i], sep = "/"))
        mmc_mRNAvarying <- mean(mRNAcount_mRNAvarying)
        outvec <- c(outvec, mmc_mRNAvarying)
    }
    
    h5closeAll()
    return(outvec)
}
# mvmc = mean of the variance in mRNA count
calculate_gene_sp_mvmc <- function(geneID, simOutputH5){    
    # outvec has 25 elements. Each element is the mvmc for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]

    mvmc_mRNAconstant <- 0  # the variance in mRNA count for mRNAconstant is 0
    outvec <- c(outvec, mvmc_mRNAconstant)
    
    # loop through the dc/r parameter space, excluding mRNAconstant
    for(i in 2:nrow(dc.r.df)){  
        mc_mRNAvarying <- h5read(simOutputH5, paste(currentGene, "gene_sp_mRNAcount_perMin", dc.r.df$paraCombo[i], sep = "/"))
        # get variance for each row(rep) and then get the mean for all reps
        mvmc_mRNAvarying <- mean(apply(mc_mRNAvarying, 1, var, na.rm = TRUE))  
        outvec <- c(outvec, mvmc_mRNAvarying)
    }
    
    h5closeAll()
    return(outvec)
}
# cvmc = coefficient variation of mRNA count
calculate_gene_sp_cvmc <- function(geneID, simOutputH5){    
    # outvec has 25 elements. Each element is the cvmc for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes, and its initial mRNA level
    currentGene <- geneNames[geneID]
    # 0 to represent mRNAconstant
    outvec <- c(outvec, 0)
    
    # loop through the dc/r parameter space, excluding mRNAconstant
    for(i in 2:nrow(dc.r.df)){  
        mRNAcount_mRNAvarying <- h5read(simOutputH5, paste(currentGene, "gene_sp_mRNAcount_perMin", dc.r.df$paraCombo[i], sep = "/"))
        # mmc = mean mRNA count
        mmc_mRNAvarying <- mean(mRNAcount_mRNAvarying) 
        # sdmc = standard deviation for each row(rep) and then get the mean for all reps
        sdmc_mRNAvarying <- mean(apply(mRNAcount_mRNAvarying, 1, sd, na.rm = TRUE)) 
        # cvmc = coefficient of variation
        cvmc_mRNAvarying <- sdmc_mRNAvarying/mmc_mRNAvarying 
        outvec <- c(outvec, cvmc_mRNAvarying)
    }
    
    h5closeAll()
    return(outvec)
}
#"mRNA_lifeTimes", 1st level: 4839 genes, 2nd: dtype, 3rd: dc/r combo or ctrl
# 4th:50 X 100 ( = 5000 life time data point, some spots will be filled with NAs since not all genes would have so many life times collected), the minimum distribution should have >400 life times collected.
# mml- mean mRNA lifetimes
calculate_gene_sp_mml <- function(geneID, simOutputH5){   
    # outvec has 25 elements. Each element is the cvmc for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]

    # loop through the dc/r parameter space
    for(i in 1:nrow(dc.r.df)){  
        ml <- h5read(simOutputH5, paste(currentGene, "mRNA_lifeTimes", dc.r.df$paraCombo[i], sep = "/"))  
        # mRNA life time averaged over simulation time
        mml <- mean(ml, na.rm = TRUE)
        outvec <- c(outvec, mml)
    }
    
    h5closeAll()
    return(outvec)
}
# vml- variance in mRNA lifetimes
calculate_gene_sp_vml <- function(geneID,simOutputH5){    
    # outvec has 25 elements. Each element is the vml for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]

    # loop through the dc/r parameter space
    for(i in 1:nrow(dc.r.df)){  
        ml <- h5read(simOutputH5, paste(currentGene, "mRNA_lifeTimes", dc.r.df$paraCombo[i], sep = "/"))
        # variance in mRNA life time among 5000 values (or maybe less than 5000 filled with NAs)
        vml <- var(as.numeric(ml), na.rm = TRUE)   
        outvec <- c(outvec, vml)
    }
    
    h5closeAll()
    return(outvec)
}
# cvml- CV in mRNA lifetimes
calculate_gene_sp_cvml <- function(geneID, simOutputH5){    
    # outvec has 25 elements. Each element is the cvml for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]

    # loop through the dc/r parameter space
    for(i in 1:nrow(dc.r.df)){  
        # mRNA lifetimes averaged over simulation time
        ml <- h5read(simOutputH5, paste(currentGene, "mRNA_lifeTimes", dc.r.df$paraCombo[i], sep = "/"))  
        mml <- mean(ml, na.rm = TRUE)
        # sdml = standard deviation in mRNA life time among 5000 values (or maybe less than 10000 filled with NAs)
        sdml <- sd(as.numeric(ml), na.rm = TRUE)   
        cvml <- ifelse(mml != 0, sdml/mml, 0) 
        outvec <- c(outvec, cvml)
    }
    
    h5closeAll()
    return(outvec)
}
# mmdr- mean mRNA decay rates
calculate_gene_sp_mmdr <- function(geneID, simOutputH5){     
    # outvec has 25 elements. Each element is the mmdr for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]

    # loop through the dc/r parameter space 
    for(i in 1:nrow(dc.r.df)){  
        # ml = mRNA life time averaged over simulation time
        ml <- h5read(simOutputH5, paste(currentGene, "mRNA_lifeTimes", dc.r.df$paraCombo[i], sep = "/"))  
        # mml = mean mRNA life time averaged over 5000 values (or maybe less than 10000 filled with NAs)
        mml <- mean(ml, na.rm = TRUE)  
        # decay rate = 1/mean lifetime
        mmdr <- 1/mml 
        
        outvec <- c(outvec, mmdr)
    }
    
    h5closeAll()
    return(outvec)
}
#"gene_sp_mRNAmarkedDecay_perMin", 1st level: 4839 genes, 2nd: dtype, 3rd: dc/r combo or mRNAconstant, 4th: 50 rep X 720 min
# mmmd- mean mRNAs marked for decay 
calculate_gene_sp_mmmd <- function(geneID, simOutputH5){    
    # outvec has 25 elements. Each element is the mmmd (# of mRNA marked for decay averaged over simTimeMin and techReps for certain geneID) for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]
    
    # loop through the dc/r parameter space
    for(i in 1:nrow(dc.r.df)){  
        mmd <- h5read(simOutputH5, paste(currentGene, "gene_sp_mRNAmarkedDecay_perMin", dc.r.df$paraCombo[i], sep = "/")) 
        # mean mRNA marked for decay over tech rep and simTimeMin
        mmmd <- mean(mmd)  
        outvec <- c(outvec, mmmd)
    }
    
    h5closeAll()
    return(outvec)
}
# mmbr =  mean mRNA-averaged bound ribosome
calculate_gene_sp_mmbr <- function(geneID, simOutputH5){    
    # outvec has 25 elements. Each element is the mmbr for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]
    
    # loop through the dc/r parameter space
    for(i in 1:nrow(dc.r.df)){  
        ribocount <- h5read(simOutputH5, paste(currentGene, "gene_sp_totBoundRibo_perMin", dc.r.df$paraCombo[i], sep = "/"))
        mRNAcount <- h5read(simOutputH5, paste(currentGene, "gene_sp_mRNAcount_perMin", dc.r.df$paraCombo[i], sep = "/"))
        # total number of bound ribos per gene per minute per rep now divided by real time mRNA count
        mbr <- ribocount/mRNAcount 
        # change all the "Inf"s to "Nan"s
        mbr[!is.finite(mbr)] <- NaN 
        # number of bound ribos per mRNA averaged over time and tech reps
        mmbr <- mean(mbr, na.rm = TRUE) 

        outvec <- c(outvec, mmbr)
    }
    
    h5closeAll()
    return(outvec)
}
# mtbr =  mean total bound ribosome (total = all mRNAs for a single gene)
calculate_gene_sp_mtbr <- function(geneID, simOutputH5){    
    # outvec has 25 elements. Each element is the mtbr for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]
    
    # loop through the dc/r parameter space 
    for(i in 1:nrow(dc.r.df)){  
        tbr <- h5read(simOutputH5, paste(currentGene, "gene_sp_totBoundRibo_perMin", dc.r.df$paraCombo[i], sep = "/"))
        # number of total bound ribos averaged over time and tech reps for each gene
        mtbr <- mean(tbr)
        outvec <- c(outvec, mtbr)
    }
    
    h5closeAll()
    return(outvec)
}
# mvtbr = mean variance in the total bound ribosomes
calculate_gene_sp_mvtbr <- function(geneID, simOutputH5){    
    # outvec has 25 elements. Each element is the mvtbr for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector() 
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]
    
    # loop through the dc/r parameter space
    for(i in 1:nrow(dc.r.df)){   
        vtbr <- h5read(simOutputH5, paste(currentGene, "gene_sp_varianceBoundRibo_perMin", dc.r.df$paraCombo[i], sep = "/"))
        # of bound ribos per mRNA averaged over time and tech reps
        mvtbr <- mean(vtbr) 
        outvec <- c(outvec, mvtbr)
    }
    
    h5closeAll()
    return(outvec)
}
# mtt = mean translation time (among all ribosomes for a gene)
calculate_gene_sp_mtt <- function(geneID, simOutputH5){  
    # outvec has 25 elements. Each element is the mtt for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector()
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]
    
    # loop through the dc/r parameter space
    for(i in 1:nrow(dc.r.df)){
        # att = average translation time among all the ribos
        att <- h5read(simOutputH5, paste(currentGene, "gene_totetimes", dc.r.df$paraCombo[i], sep = "/"))[, 2] 
        mtt <- mean(att)
        outvec <- c(outvec, mtt)
    }
    
    h5closeAll()
    return(outvec)
}
# mvtt = mean of variance in translation time (var among all ribosomes for a gene)
calculate_gene_sp_mvtt <- function(geneID, simOutputH5){  
    # outvec has 25 elements. Each element is the mvtt for the 1 mRNAconstant + 24 different dc/r combos
    outvec <- vector()
    
    # current gene name out of the 4839 genes
    currentGene <- geneNames[geneID]
    
    # loop through the dc/r parameter space
    for(i in 1:nrow(dc.r.df)){ 
        # vtt = variance in translation time among all the ribos
        vtt <- h5read(simOutputH5, paste(currentGene, "gene_totetimes", dc.r.df$paraCombo[i], sep = "/"))[, 3]
        mvtt <- mean(vtt)
        outvec <- c(outvec, mvtt)
    }
    
    h5closeAll()
    return(outvec)
}

#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DON’T RUN FOLLOWING CHUNKS UNLESS THE FEATHER FILES DON’T ALREADY EXIST ### The following chunks utilzie multithreading, make sure the mc.cores are set to approperiate numbers.

print(Sys.time())
[1] "2021-12-07 15:31:53 EST"
mpsrList <- mclapply(1:4839, function(x){calculate_gene_sp_mpsr(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:32:23 EST"
# ncol = 25, nrow = 4839
mpsrAllgeneAlldcr <- as_tibble(do.call(rbind, mpsrList))

write_feather(mpsrAllgeneAlldcr, path = "../calculatedMetrics/mpsrAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:32:23 EST"
mvpsList <- mclapply(1:4839, function(x){calculate_gene_sp_mvps(geneID = x, simOutputH5= simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:33:12 EST"
# ncol = 25, nrow = 4839
mvpsAllgeneAlldcr <- as_tibble(do.call(rbind, mvpsList))

write_feather(mvpsAllgeneAlldcr, path = "../calculatedMetrics/mvpsAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:33:13 EST"
cvpsList <- mclapply(1:4839, function(x){calculate_gene_sp_cvps(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# 12:44 began 12:49 finish
print(Sys.time())
[1] "2021-12-07 15:34:02 EST"
# ncol = 25, nrow = 4839
cvpsAllgeneAlldcr <- as_tibble(do.call(rbind, cvpsList))

write_feather(cvpsAllgeneAlldcr, path = "../calculatedMetrics/cvpsAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-09 16:43:34 EST"
cpsrList <- mclapply(1:nrow(dc.r.df), function(x){calculate_para_sp_cpsr(pid = x)}, mc.cores = 45)
print(Sys.time())
[1] "2021-12-07 15:35:17 EST"
# pid = parameter id = 1:25, 1 = mRNAconstant, 2:25 = different dc/r combos, output is a number
mcpsrList <- mclapply(1:nrow(dc.r.df), function(x){calculate_para_sp_mcpsr(pid = x)}, mc.cores = 45)
# took 2min
print(Sys.time())
[1] "2021-12-07 15:36:30 EST"
# mcpsrAlldcr is a vector of 25 numbers
mcpsrAlldcr <- as_tibble(MCPSR = unlist(mcpsrList),
                       paraID = dc.r.df$paraID)
Error in as_tibble.default(MCPSR = unlist(mcpsrList), paraID = dc.r.df$paraID) : 
  argument "x" is missing, with no default
print(Sys.time())
[1] "2021-12-07 15:40:11 EST"
mteList <- mclapply(1:4839, function(x){calculate_gene_sp_mte(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
print(Sys.time())
[1] "2021-12-07 15:41:22 EST"
# ncol = 25, nrow = 4839
mteAllgeneAlldcr <- as_tibble(do.call(rbind, mteList))

write_feather(mteAllgeneAlldcr, path = "../calculatedMetrics/mteAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:41:22 EST"
mvteList <- mclapply(1:4839, function(x){calculate_gene_sp_mvte(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 3 min
print(Sys.time())
[1] "2021-12-07 15:42:40 EST"
# ncol = 25, nrow = 4839
mvteAllgeneAlldcr <- as_tibble(do.call(rbind, mvteList))

write_feather(mvteAllgeneAlldcr, path = "../calculatedMetrics/mvteAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:42:40 EST"
mmcList <- mclapply(1:4839, function(x){calculate_gene_sp_mmc(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:43:13 EST"
# ncol = 25, nrow = 4839
mmcAllgeneAlldcr <- as_tibble(do.call(rbind, mmcList))

write_feather(mmcAllgeneAlldcr, path = "../calculatedMetrics/mmcAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:43:13 EST"
mvmcList <- mclapply(1:4839, function(x){calculate_gene_sp_mvmc(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:43:59 EST"
# ncol = 25, nrow = 4839
mvmcAllgeneAlldcr <- as_tibble(do.call(rbind, mvmcList))

write_feather(mvmcAllgeneAlldcr, path = "../calculatedMetrics/mvmcAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:43:59 EST"
cvmcList <- mclapply(1:4839, function(x){calculate_gene_sp_cvmc(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# 12:44 began 12:49 finish
print(Sys.time())
[1] "2021-12-07 15:44:47 EST"
# ncol = 25, nrow = 4839
cvmcAllgeneAlldcr <- as_tibble(do.call(rbind, cvmcList))

write_feather(cvmcAllgeneAlldcr, path = "../calculatedMetrics/cvmcAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:44:47 EST"
mmlList <- mclapply(1:4839, function(x){calculate_gene_sp_mml(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:45:16 EST"
# ncol = 25, nrow = 4839
mmlAllgeneAlldcr <- as_tibble(do.call(rbind, mmlList))

write_feather(mmlAllgeneAlldcr, path = "../calculatedMetrics/mmlAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:45:16 EST"
vmlList <- mclapply(1:4839, function(x){calculate_gene_sp_vml(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:45:47 EST"
# ncol = 25, nrow = 4839
vmlAllgeneAlldcr <- as_tibble(do.call(rbind, vmlList))

write_feather(vmlAllgeneAlldcr, path = "../calculatedMetrics/vmlAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:45:47 EST"
cvmlList <- mclapply(1:4839, function(x){calculate_gene_sp_cvml(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:46:18 EST"
# ncol = 25, nrow = 4839
cvmlAllgeneAlldcr <- as_tibble(do.call(rbind, cvmlList))

write_feather(cvmlAllgeneAlldcr, path = "../calculatedMetrics/cvmlAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:46:18 EST"
mmdrList <- mclapply(1:4839, function(x){calculate_gene_sp_mmdr(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:46:46 EST"
# ncol = 25, nrow = 4839
mmdrAllgeneAlldcr <- as_tibble(do.call(rbind, mmdrList))

write_feather(mmdrAllgeneAlldcr, path = "../calculatedMetrics/mmdrAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:46:46 EST"
mmmdList <- mclapply(1:4839, function(x){calculate_gene_sp_mmmd(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 3 min
print(Sys.time())
[1] "2021-12-07 15:47:22 EST"
# ncol = 25, nrow = 4839
mmmdAllgeneAlldcr <- as_tibble(do.call(rbind, mmmdList))

write_feather(mmmdAllgeneAlldcr, path = "../calculatedMetrics/mmmdAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:47:22 EST"
mmbrList <- mclapply(1:4839, function(x){calculate_gene_sp_mmbr(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:48:35 EST"
# ncol = 25, nrow = 4839
mmbrAllgeneAlldcr <- as_tibble(do.call(rbind, mmbrList))

write_feather(mmbrAllgeneAlldcr, path = "../calculatedMetrics/mmbrAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:48:35 EST"
mtbrList <- mclapply(1:4839, function(x){calculate_gene_sp_mtbr(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:49:11 EST"
# ncol = 25, nrow = 4839
mtbrAllgeneAlldcr <- as_tibble(do.call(rbind, mtbrList))

write_feather(mtbrAllgeneAlldcr, path = "../calculatedMetrics/mtbrAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:49:12 EST"
mvtbrList <- mclapply(1:4839, function(x){calculate_gene_sp_mvtbr(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:49:51 EST"
# ncol = 25, nrow = 4839
mvtbrAllgeneAlldcr <- as_tibble(do.call(rbind, mvtbrList))

write_feather(mvtbrAllgeneAlldcr, path = "../calculatedMetrics/mvtbrAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:49:51 EST"
mttList <- mclapply(1:4839, function(x){calculate_gene_sp_mtt(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:50:18 EST"
# ncol = 25, nrow = 4839
mttAllgeneAlldcr <- as_tibble(do.call(rbind, mttList))

write_feather(mttAllgeneAlldcr, path = "../calculatedMetrics/mttAllgeneAlldcr.feather")
print(Sys.time())
[1] "2021-12-07 15:50:18 EST"
mvttList <- mclapply(1:4839, function(x){calculate_gene_sp_mvtt(geneID = x, simOutputH5 = simOutputH5)}, mc.cores = 45)
# took 2min to run
print(Sys.time())
[1] "2021-12-07 15:50:44 EST"
# ncol = 25, nrow = 4839
mvttAllgeneAlldcr <- as_tibble(do.call(rbind, mvttList))

write_feather(mvttAllgeneAlldcr, path = "../calculatedMetrics/mvttAllgeneAlldcr.feather")

calculating the mean number of free ribos (averaged over simTimeMin and techReps) for all dc.r.combos

# MFR = mean free ribo
# RMFR = relative mean free ribo
mfr <- c() 
# loop through the dc/r parameter space
for(i in 1:nrow(dc.r.df)){ 
    # free_ribo averaged by simTimeMin and techReps
    mfr <- c(mfr, mean(h5read(simOutputH5, paste("free_ribo_tRNA_perMin", dc.r.df$paraCombo[i], "ribo", sep = "/")), na.rm = TRUE))
}

rmfr <- mfr/mfr[1]
rmfr_df <- as_tibble(data.frame(RMFR = rmfr,
                      MFR = mfr,
                      paraID = dc.r.df$paraID))

getting all input features and output results together in allSimInputOutput

# convert any input dataframes (e.g. mteAllgeneAlldcr) to long format
df.convert.fun <- function(x){   
    inputdf = calculatedMetrics.list[[x]]
    dfname = str_sub(toupper(names(calculatedMetrics.list)[[x]]), 1, -14)

    inputdf %>%
        mutate(ORF = simInputFeatures$ORF) %>%
        gather_(key_col = "paraID", value_col = dfname, gather_cols = colnames(inputdf)[1:nrow(dc.r.df)])

}

# Read in the files that conatins "AllgeneAlldcr.feather", these files can be left_joined by "paraID" and "ORF"
files.locs <- dir("../calculatedMetrics", pattern = "AllgeneAlldcr.feather", full.names = TRUE)

# read_feather for all the files in this location
calculatedMetrics.list <- sapply(files.locs, read_feather, simplify = FALSE)  
# exclude the path and only extract the data frame names, e.g. "mmcAllgeneAlldcr"
names(calculatedMetrics.list) <- str_sub(names(calculatedMetrics.list), nchar("../calculatedMetrics/")+1, -9)   


# divide mte of 25 dc/r combo by mte of the mRNAconstant = rmte, relative mean translation efficiency
# X1 = mRNA constant, X2:X25 = mRNAvarying
# dim(rmteAllgeneAlldcr) = 4839 X 25
calculatedMetrics.list$rmpsrAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$mpsrAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]})))
calculatedMetrics.list$rmvpsAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$mvpsAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]})))
calculatedMetrics.list$rcvpsAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$cvpsAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]}))) #x[1] is for mRNAconstant
calculatedMetrics.list$rmteAllgeneAlldcr <-  as_tibble(t(apply(calculatedMetrics.list$mteAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]}))) #x[1] is for mRNAconstant
calculatedMetrics.list$rmvteAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$mvteAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]})))
calculatedMetrics.list$cvmcAllgeneAlldcr <- sqrt(calculatedMetrics.list$mvmcAllgeneAlldcr)/calculatedMetrics.list$mmcAllgeneAlldcr  # mRNA count coefficient of variation
calculatedMetrics.list$rmmcAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$mmcAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]})))
calculatedMetrics.list$rmmdrAllgeneAlldcr <- as_tibble(do.call(rbind, lapply(1:4839, function(geneID){calculatedMetrics.list$mmdrAllgeneAlldcr[geneID, ]/simInputFeatures$mRNADecRateNeymotin_sec[geneID]})))  # for X1 this will be 0,  for the ~30 genes whose GreshamDecRate = 0 this will be NaN b/c 0/0 = NaN
calculatedMetrics.list$rmttAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$mttAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]})))
calculatedMetrics.list$rmvttAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$mvttAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]})))
calculatedMetrics.list$mhlAllgeneAlldcr <- as_tibble(log(2)/calculatedMetrics.list$mmdrAllgeneAlldcr) # mean half life
calculatedMetrics.list$mmdpAllgeneAlldcr <- as_tibble(calculatedMetrics.list$mmmdAllgeneAlldcr/calculatedMetrics.list$mmcAllgeneAlldcr)
calculatedMetrics.list$mrdAllgeneAlldcr <- as_tibble(calculatedMetrics.list$mmbrAllgeneAlldcr/simInputFeatures$geneLength_codon) #ribosome density=number of ribosomes N divided by the CDS length L
calculatedMetrics.list$rmrdAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$mrdAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]}))) #x[1] is for mRNAconstant
calculatedMetrics.list$rmtbrAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$mtbrAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]}))) #x[1] is for mRNAconstant
calculatedMetrics.list$rmvtbrAllgeneAlldcr <- as_tibble(t(apply(calculatedMetrics.list$mvtbrAllgeneAlldcr, 1, function(x){x[1:nrow(dc.r.df)]/x[1]}))) #x[1] is for mRNAconstant

# convert all the calculatedMetrics.list dataframes to long format
calculatedMetricsLong.list <- lapply(1:length(calculatedMetrics.list), df.convert.fun)

mcpsrAlldcr <- read_feather("../calculatedMetrics/mcpsrAlldcr.feather")

# Join all the dataframes in calculatedMetrics.list
allSimInputOutput <- 
    calculatedMetricsLong.list %>%
        purrr::reduce(left_join, by = c("paraID" = "paraID", "ORF" = "ORF")) %>%
        left_join(., mcpsrAlldcr, "paraID") %>%
        left_join(., rmfr_df, by = "paraID") %>%
        left_join(., dc.r.df, "paraID") %>%
        left_join(., simInputFeatures, by = "ORF")

write_feather(allSimInputOutput, path = "../allSimInputOutput.feather")

allSimInputOutput %>%
    filter(ORF == "YBR208C")

allSimInputOutput %>%
    filter(ORF == "YJR109C")

allSimInputOutput %>%
    filter(ORF == "YAL001C")

allSimInputOutput %>%
    filter(ORF == "YAL034W-A")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKTG9hZCBsaWJyYXJpZXMgYW5kIHB1YmxpYyB2YXJpYWJsZXMKYGBge3IsIGluY2x1ZGUgPSBGQUxTRX0gCiMgVGhpcyBjaHVuayB3aWxsIGJlIGV2YWx1YXRlZCBidXQgdGhlIG91dHB1dCBpcyBzdXBwcmVzc2VkCnJtYXJrZG93bjo6cmVuZGVyKCIuLi8uLi9wdWJsaWNWYXJpYWJsZXMvY3JlYXRlUHVibGljVmFyaWFibGVzLlJtZCIpCmBgYAoKCmBgYHtyfQojIEZpbGUgdGhhdCBjb250YWlucyBzaW11bGF0aW9uIG91dHB1dCBkYXRhIGluIGEgSERGNSBkaXJlY3Rvcnkgc3RydWN0dXJlIHNwZWNpZmllZCBpbiAiL3B1YmxpY1ZhcmlhYmxlcy9jcmVhdGVQdWJsaWNWYXJpYWJsZXMuUm1kIgpzaW1PdXRwdXRINSA8LSBwYXN0ZTAoIi4uLy4uL2RhdGFQcm9jZXNzaW5nL3NpbU91dHB1dEg1RGF0YS8iLCBleHBlcmltZW50SUQsICJfb3V0cHV0Lmg1IikKCiMgVGhpcyBmb2xkZXIgY29udGFpbnMgcmF3IG91dHB1dCBmaWxlcyBmcm9tIHRoZSBzaW11bGF0aW9ucy4gVGhpcyBpcyBuZWVkZWQgZm9yIGNhbGN1bGF0ZV9wYXJhX3NwX21jcHNyKCkKcmF3U2ltT3V0Rm9sZGVyIDwtICIvdGVhbS9iYXRjaF9TTU9UTlQvZXhwZXJpbWVudDFfb3V0cHV0IgpgYGAKCgoKIyMjIFJlZmVyIHRvIFN1cHBsZW1lbnRhcnkgTWV0aG9kcyBmb3IgdGhlIG1hdGhlbWF0aWNhbCBlcXVhdGlvbnMgb2YgZWFjaCBvZiB0aGUgZm9sbG93aW5nIGNhbGN1bGF0ZWQgbWV0cmljcy4KYGBge3J9CiMgbXBzciA9IG1lYW4gcHJvdGVpbiBzeW50aGVzaXMgcmF0ZXM7ICAKY2FsY3VsYXRlX2dlbmVfc3BfbXBzciA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgICAKICAgICMgb3V0dmVjIGhhcyAyNSBlbGVtZW50cy4gRWFjaCBlbGVtZW50IGlzIHRoZSBtcHNyICgjIG9mIHJpYm9zIHRoYXQgaG9wIG9mZiBwZXIgbWluIGZvciBhIGdlbmUpIGZvciB0aGUgMSBtUk5BY29uc3RhbnQgKyAyNCBkaWZmZXJlbnQgZGMvciBjb21ib3MKICAgIG91dHZlYyA8LSB2ZWN0b3IoKSAKICAgIAogICAgIyBjdXJyZW50IGdlbmUgbmFtZSBvdXQgb2YgdGhlIDQ4MzkgZ2VuZXMKICAgIGN1cnJlbnRHZW5lIDwtIGdlbmVOYW1lc1tnZW5lSURdCgogICAgIyBtYXRyaXggdGhhdCBjb250YWlucyBjb3VudEVsbmcgaW5mbyBmb3IgY3VycmVudCBzZWxlY3RlZCBnZW5lIGluIG1STkFjb25zdGFudCBkYXRhCiAgICAjIHBzID0gcHJvdGVpbiBzeW50aGVzaXMKICAgICMgbXBzciA9IG1lYW4gcHJvdGVpbiBzeW50aGVzaXMgcmF0ZQogICAgcHNfbVJOQWNvbnN0YW50IDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUwKGN1cnJlbnRHZW5lLCAiL2dlbmVfc3BfY291bnRFbG5nX3Blck1pbi9tUk5BY29uc3RhbnQiKSkKICAgIG1wc3JfbVJOQWNvbnN0YW50IDwtIG1lYW4ocHNfbVJOQWNvbnN0YW50KQogICAgb3V0dmVjIDwtIGMob3V0dmVjLCBtcHNyX21STkFjb25zdGFudCkKICAgIAogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlIHRvIGNhbGN1bGF0ZSB0aGUgbWVhbl9jb3VudEVsbmdfbVJOQXZhcnlpbmcKICAgIGZvcihpIGluIDI6bnJvdyhkYy5yLmRmKSl7CiAgICAgICAgcHNfbVJOQXZhcnlpbmcgPC0gaDVyZWFkKHNpbU91dHB1dEg1LCBwYXN0ZShjdXJyZW50R2VuZSwgImdlbmVfc3BfY291bnRFbG5nX3Blck1pbiIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCBzZXAgPSAiLyIpKQogICAgICAgIG1wc3JfbVJOQXZhcnlpbmcgPC0gbWVhbihwc19tUk5BdmFyeWluZykKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG1wc3JfbVJOQXZhcnlpbmcpCiAgICB9CiAgICAKICAgIGg1Y2xvc2VBbGwoKQogICAgcmV0dXJuKG91dHZlYykKfQpgYGAKCgpgYGB7cn0KIyBtdnBzID0gbWVhbiBvZiB0aGUgKHZhcmlhbmNlIGluIHByb3RlaW4gc3ludGhlc2lzIGFtb25nIHNpbXUgdGltZXMpIGFtb25nIHRlY2huaWNhbCByZXBsaWNhdGVzIApjYWxjdWxhdGVfZ2VuZV9zcF9tdnBzIDwtIGZ1bmN0aW9uKGdlbmVJRCwgc2ltT3V0cHV0SDUpeyAgCiAgICAjIG91dHZlYyBoYXMgMjUgZWxlbWVudHMuIEVhY2ggZWxlbWVudCBpcyB0aGUgbXZwcyBmb3IgdGhlIDEgbVJOQWNvbnN0YW50ICsgMjQgZGlmZmVyZW50IGRjL3IgY29tYm9zCiAgICBvdXR2ZWMgPC0gdmVjdG9yKCkgCiAgICAKICAgICMgY3VycmVudCBnZW5lIG5hbWUgb3V0IG9mIHRoZSA0ODM5IGdlbmVzCiAgICBjdXJyZW50R2VuZSA8LSBnZW5lTmFtZXNbZ2VuZUlEXQogICAgCiAgICAjIG1hdHJpeCB0aGF0IGNvbnRhaW5zIGNvdW50RWxuZyBpbmZvIGZvciBjdXJyZW50IHNlbGVjdGVkIGdlbmUgaW4gbVJOQWNvbnN0YW50IGRhdGEKICAgIHBzX21STkFjb25zdGFudCA8LSBoNXJlYWQoc2ltT3V0cHV0SDUsIHBhc3RlMChjdXJyZW50R2VuZSwgIi9nZW5lX3NwX2NvdW50RWxuZ19wZXJNaW4vbVJOQWNvbnN0YW50IikpCiAgICAjIGdldCB2YXJpYW5jZSBmb3IgZWFjaCByb3cocmVwKSBhbmQgdGhlbiBnZXQgdGhlIG1lYW4gZm9yIGFsbCByZXBzCiAgICBtdnBzX21STkFjb25zdGFudCA8LSBtZWFuKGFwcGx5KHBzX21STkFjb25zdGFudCwgMSwgdmFyKSkgIAogICAgb3V0dmVjIDwtIGMob3V0dmVjLCBtdnBzX21STkFjb25zdGFudCkKICAgIAogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlIAogICAgZm9yKGkgaW4gMjpucm93KGRjLnIuZGYpKXsgCiAgICAgICAgIyBwc19tUk5BdmFyeWluZyBpcyBhIDUwIFggNzIwIG1hdHJpeAogICAgICAgIHBzX21STkF2YXJ5aW5nIDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJnZW5lX3NwX2NvdW50RWxuZ19wZXJNaW4iLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgc2VwID0gIi8iKSkKICAgICAgICAjIGdldCB2YXJpYW5jZSBmb3IgZWFjaCByb3cgKHJlY2ggcmVwKSBhbmQgdGhlbiBnZXQgdGhlIG1lYW4gZm9yIGFsbCB0ZWNobmlhbCByZXBzCiAgICAgICAgbXZwc19tUk5BdmFyeWluZyA8LSBtZWFuKGFwcGx5KHBzX21STkF2YXJ5aW5nLCAxLCB2YXIsIG5hLnJtID0gVFJVRSkpICAKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG12cHNfbVJOQXZhcnlpbmcpCiAgICB9CiAgICAKICAgIGg1Y2xvc2VBbGwoKQogICAgcmV0dXJuKG91dHZlYykKfQpgYGAKCmBgYHtyfQojIGN2cHMgPSBjb2VmZmljaWVudCB2YXJpYXRpb24gb2YgdG90YWwgcHJvdGVpbiBwcm9kdWNlZCBwZXIgbWludXRlCmNhbGN1bGF0ZV9nZW5lX3NwX2N2cHMgPC0gZnVuY3Rpb24oZ2VuZUlELCBzaW1PdXRwdXRINSl7ICAKICAgICMgb3V0dmVjIGlzIGEgdmVjdG9yIHRoYXQgaGFzIDI1IGVsZW1lbnRzLiBFYWNoIGVsZW1lbnQgaXMgdGhlIG12cHMgZm9yIHRoZSAxIG1STkFjb25zdGFudCArIDI0IGRpZmZlcmVudCBkYy9yIGNvbWJvcwogICAgb3V0dmVjIDwtIHZlY3RvcigpIAogICAgCiAgICAjIGN1cnJlbnQgZ2VuZSBuYW1lIG91dCBvZiB0aGUgNDgzOSBnZW5lcwogICAgY3VycmVudEdlbmUgPC0gZ2VuZU5hbWVzW2dlbmVJRF0KICAgIAogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlIHRvIGNhbGN1bGF0ZSB0aGUgbWVhbl9jb3VudEVsbmdfbVJOQXZhcnlpbmcKICAgIGZvcihpIGluIDE6bnJvdyhkYy5yLmRmKSl7IAogICAgICAgIHBzIDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJnZW5lX3NwX2NvdW50RWxuZ19wZXJNaW4iLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgc2VwID0gIi8iKSkKICAgICAgICBtcHNyIDwtIG1lYW4ocHMpICMgbWVhbgogICAgICAgICMgZ2V0IHN0YW5kYXJkIGRldmlhdGlvbiBmb3IgZWFjaCByb3cocmVwKSBhbmQgdGhlbiBnZXQgdGhlIG1lYW4gZm9yIGFsbCByZXBzCiAgICAgICAgc2RwcyA8LSBtZWFuKGFwcGx5KHBzLCAxLCBzZCwgbmEucm0gPSBUUlVFKSkgIAogICAgICAgICMgY3ZwcyA9IGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbiBvZiBwcm90ZWluIHN5bnRoZXNpcwogICAgICAgIGN2cHMgPC0gc2Rwcy9tcHNyIAogICAgICAgIG91dHZlYyA8LSBjKG91dHZlYywgY3ZwcykKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKCmBgYHtyfQojIGNwc3IgPSBjZWxsdWxhciBwcm90ZWluIHN5bnRoZXNpcyByYXRlLCB0aGlzIGZ1bmN0aW9uIHJldHVybnMgdGhlIGNwc3IgZm9yIDUwIHRlY2huaWNhbCByZXBsaWNhdGUgdGhhdCBpcyBvZiB0aGUgc2FtZSBwYXJhQ29tYm8sIGl0IGlzIHRoZXJlZm9yZSBub3Qgam9pbmVkIGludG8gYWxsU2ltSW5wdXRPdXRwdXQKIyBwaWQgPSBwYXJhbWV0ZXIgaWQsIDE6MjUsIDEgPSBtUk5BY29uc3RhbnQsIDI6MjUgPSBkaWZmZXJlbnQgZGMvciBjb21ib3MsIG91dHB1dCBpcyBhIG51bWJlcgpjYWxjdWxhdGVfcGFyYV9zcF9jcHNyIDwtIGZ1bmN0aW9uKHBpZCl7ICAKICAgICMgdGhlcmUgYXJlIDI1IHBhcmEgY29tYm8gKiA1MCByZXBzID0gMTI1MCBmaWxlcyBpbiB0aGlzIGZvbGRlciAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgY291bnRFbG5nRm9sZGVyIDwtIHBhc3RlMChyYXdTaW1PdXRGb2xkZXIsICIvZ2VuZV9zcF9jb3VudEVsbmdfcGVyTWluLyIpIAogICAgCiAgICAjIE4gPSAjIG9mIHRlY2ggcmVwcywgaGVyZSBOY291bnRFbG5nRmlsZXMgY29udGFpbnMgNTAgZmlsZSBjb250ZW50cwogICAgaWYocGlkID09IDEpewogICAgICAgIE5jb3VudEVsbmdGaWxlcyA8LSBsaXN0LmZpbGVzKGNvdW50RWxuZ0ZvbGRlciwgcGF0dGVybiA9IGdsb2IycngocGFzdGUwKCIqZGNfMF9yXzBfbVJOQWNvbnN0YW50KiIpKSkKICAgIH1lbHNlewogICAgICAgIE5jb3VudEVsbmdGaWxlcyA8LSBsaXN0LmZpbGVzKGNvdW50RWxuZ0ZvbGRlciwgcGF0dGVybiA9IGdsb2IycngocGFzdGUwKCIqIiwgZGMuci5kZiRwYXJhQ29tYm9bcGlkXSwgIl9hbGxHZW5lc0RlY3JFcXVhbHNTeW5yU2NhbGluZyoiKSkpCiAgICB9CiAgICAKICAgIGNwc3IuYWxsLnRlY2hSZXAgPC0gYygpCiAgICBmb3IoaWkgaW4gMTpudW1UZWNoUmVwcyl7IAogICAgICAgICMgY3BzID0gY2VsbHVsYXIgcHJvdGVpbiBzeW50aGVzaXMsIGlzIGEgdmVjdG9yIHRoYXQgY29udGFpbnMgNzE5IG51bWJlcnMoNzIwLTEpCiAgICAgICAgY3BzID0gYXBwbHkocmVhZC50YWJsZShmaWxlID0gcGFzdGUwKGNvdW50RWxuZ0ZvbGRlciwgTmNvdW50RWxuZ0ZpbGVzW2lpXSkpWywgMjo0ODQwXSwgMSwgc3VtKSAjIGdldCB0aGUgc3VtIG9mIGVhY2ggbGluZSBpbiBhIHNpbmdsZSBmaWxlCiAgICAgIAogICAgICAgICMgY3BzIGdpdmUgYSB2ZWN0b3Igb2YgNzE5IG51bWJlcnMsIHRoZW4geW91IGdldCB0aGUgbWVhbiBvZiB0aG9zZSA3MTkgbnVtYmVycwogICAgICAgICMgY3BzciA9IGNlbGx1bGFyIHByb3RlaW4gc3ludGhlc2lzIHJhdGUKICAgICAgICBjcHNyIDwtIG1lYW4oY3BzKQogICAgICAgIGNwc3IuYWxsLnRlY2hSZXAgPC0gYyhjcHNyLmFsbC50ZWNoUmVwLCBjcHNyKSAgIyB0aGlzIHdpbGwgY29udGFpbiA1MCBudW1iZXJzCiAgICB9CgogICAgcmV0dXJuKGNwc3IuYWxsLnRlY2hSZXApCn0KYGBgCgoKYGBge3J9CiMgbWNwc3IgPSBtZWFuIGNlbGx1bGFyIHByb3RlaW4gc3ludGhlc2lzIHJhdGUgYW1vbmcgdGVjaG5pY2FsIHJlcHMKIyBwYXJhbWV0ZXIgaWQsIDE6MjUsIDEgPSBtUk5BY29uc3RhbnQsIDI6MjUgPSBkaWZmZXJlbnQgZGMvciBjb21ib3MsIG91dHB1dCBpcyBhIG51bWJlcgpjYWxjdWxhdGVfcGFyYV9zcF9tY3BzciA8LSBmdW5jdGlvbihwaWQpeyAgCiAgICAjIHRoZXJlIGFyZSAyNSBwYXJhIGNvbWJvICogNTAgcmVwcyA9IDEyNTAgZmlsZXMgaW4gdGhpcyBmb2xkZXIgICAgICAgICAgICAgICAgICAKICAgIGNvdW50RWxuZ0ZvbGRlciA8LSBwYXN0ZTAocmF3U2ltT3V0Rm9sZGVyLCAiL2dlbmVfc3BfY291bnRFbG5nX3Blck1pbi8iKSAKICAgIAogICAgIyBOID0gIyBvZiB0ZWNoIHJlcHMsIGhlcmUgTmNvdW50RWxuZ0ZpbGVzIGNvbnRhaW5zIDUwIGZpbGUgY29udGVudHMKICAgIGlmKHBpZCA9PSAxKXsKICAgICAgICBOY291bnRFbG5nRmlsZXMgPC0gbGlzdC5maWxlcyhjb3VudEVsbmdGb2xkZXIsIHBhdHRlcm4gPSBnbG9iMnJ4KHBhc3RlMCgiKmRjXzBfcl8wX21STkFjb25zdGFudCoiKSkpCiAgICB9ZWxzZXsKICAgICAgICBOY291bnRFbG5nRmlsZXMgPC0gbGlzdC5maWxlcyhjb3VudEVsbmdGb2xkZXIsIHBhdHRlcm4gPSBnbG9iMnJ4KHBhc3RlMCgiKiIsIGRjLnIuZGYkcGFyYUNvbWJvW3BpZF0sICJfYWxsR2VuZXNEZWNyRXF1YWxzU3luclNjYWxpbmcqIikpKQogICAgfQogICAgCiAgICBjcHNyLmFsbC50ZWNoUmVwIDwtIGMoKQogICAgZm9yKGlpIGluIDE6bnVtVGVjaFJlcHMpewogICAgICAgICMgY3BzID0gY2VsbHVsYXIgcHJvdGVpbiBzeW50aGVzaXMsIGlzIGEgdmVjdG9yIHRoYXQgY29udGFpbnMgNzIwIG51bWJlcnMKICAgICAgICAjIGdldCB0aGUgc3VtIG9mIGVhY2ggbGluZSBpbiBhIHNpbmdsZSBmaWxlCiAgICAgICAgY3BzID0gYXBwbHkocmVhZC50YWJsZShmaWxlID0gcGFzdGUwKGNvdW50RWxuZ0ZvbGRlciwgTmNvdW50RWxuZ0ZpbGVzW2lpXSkpWywgMjo0ODQwXSwgMSwgc3VtKSAKICAgICAgICAKICAgICAgICAjIGNwc3IgPSBjZWxsdWxhciBwcm90ZWluIHN5bnRoZXNpcyByYXRlID0gZ2V0IHRoZSBtZWFuIG9mIHRob3NlIDcyMCBudW1iZXJzIGluIGNwcwogICAgICAgIGNwc3IgPC0gbWVhbihjcHMpCiAgICAgICAgIyB0aGlzIHdpbGwgY29udGFpbiA1MCBudW1iZXJzLCAxIGZvciBlYWNoIHRlY2ggcmVwCiAgICAgICAgY3Bzci5hbGwudGVjaFJlcCA8LSBjKGNwc3IuYWxsLnRlY2hSZXAsIGNwc3IpICAKICAgIH0KICAgICMgbWVhbiBvZiB0aGUgY3BzciBhbW9uZyA1MCB0ZWNobmljYWwgcmVwcwogICAgbWNwc3IgPC0gbWVhbihjcHNyLmFsbC50ZWNoUmVwKQogICAgcmV0dXJuKG1jcHNyKQp9CmBgYAoKYGBge3J9CiMgbXRlID0gbWVhbiB0cmFuc2xhdGlvbiBlZmZpY2llbmN5CmNhbGN1bGF0ZV9nZW5lX3NwX210ZSA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgICAKICAgICMgb3V0dmVjIGhhcyAyNSBlbGVtZW50cy4gRWFjaCBlbGVtZW50IGlzIHRoZSBtdGUgZm9yIHRoZSAxIG1STkFjb25zdGFudCArIDI0IGRpZmZlcmVudCBkYy9yIGNvbWJvcwogICAgb3V0dmVjIDwtIHZlY3RvcigpIAogICAgCiAgICAjIGN1cnJlbnQgZ2VuZSBuYW1lIG91dCBvZiB0aGUgNDgzOSBnZW5lcywgYW5kIGl0cyBpbml0aWFsIG1STkEgbGV2ZWwKICAgIGN1cnJlbnRHZW5lIDwtIGdlbmVOYW1lc1tnZW5lSURdCiAgICBtUk5BYWJ1bmRhbmNlQ3VycmVudEdlbmUgPC0gc2ltSW5wdXRGZWF0dXJlcyRtUk5BYWJ1bmRhbmNlW2dlbmVJRF0KICAgIAogICAgIyBtYXRyaXggdGhhdCBjb250YWlucyBjb3VudEVsbmcgaW5mbyBmb3IgY3VycmVudCBnZW5lLgogICAgIyB0ZSA9IHRyYW5zbGF0aW9uIGVmZmljaWVuY3ksIG10ZSA9IG1lYW4gdHJhbnNsYXRpb24gZWZmaWNpZW5jeQogICAgY291bnRFbG5nX21STkFjb25zdGFudCA8LSBoNXJlYWQoc2ltT3V0cHV0SDUsIHBhc3RlMChjdXJyZW50R2VuZSwgIi9nZW5lX3NwX2NvdW50RWxuZ19wZXJNaW4vbVJOQWNvbnN0YW50IikpCiAgICB0ZV9tUk5BY29uc3RhbnQgPC0gY291bnRFbG5nX21STkFjb25zdGFudC9tUk5BYWJ1bmRhbmNlQ3VycmVudEdlbmUKICAgIG10ZV9tUk5BY29uc3RhbnQgPC0gbWVhbih0ZV9tUk5BY29uc3RhbnQpCiAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG10ZV9tUk5BY29uc3RhbnQpCiAgICAKICAgICMgbG9vcCB0aHJvdWdoIHRoZSBkYy9yIHBhcmFtZXRlciBzcGFjZQogICAgZm9yKGkgaW4gMjpucm93KGRjLnIuZGYpKXsgCiAgICAgICAgY291bnRFbG5nX21STkF2YXJ5aW5nIDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJnZW5lX3NwX2NvdW50RWxuZ19wZXJNaW4iLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgc2VwID0gIi8iKSkKICAgICAgICBtUk5BY291bnRfbVJOQXZhcnlpbmcgPC0gaDVyZWFkKHNpbU91dHB1dEg1LCBwYXN0ZShjdXJyZW50R2VuZSwgImdlbmVfc3BfbVJOQWNvdW50X3Blck1pbiIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCBzZXAgPSAiLyIpKQogICAgICAgICMgdGUgPSB0cmFuc2xhdGlvbiBlZmZpY2llbmN5CiAgICAgICAgdGVfbVJOQXZhcnlpbmcgPC0gY291bnRFbG5nX21STkF2YXJ5aW5nL21STkFjb3VudF9tUk5BdmFyeWluZyAgIAogICAgICAgICMgY2hhbmdlIGFsbCB0aGUgIkluZiJzIHRvICJOYW4icwogICAgICAgIHRlX21STkF2YXJ5aW5nWyFpcy5maW5pdGUodGVfbVJOQXZhcnlpbmcpXSA8LSBOYU4gCiAgICAgICAgIyBtdGUgPSBtZWFuIHRyYW5zbGF0aW9uIHJhdGUgYXZlcmFnZWQgb3ZlciB0aW1lIGFuZCB0ZWNoIHJlcHMKICAgICAgICBtdGVfbVJOQXZhcnlpbmcgPC0gbWVhbih0ZV9tUk5BdmFyeWluZywgbmEucm0gPSBUUlVFKSAKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG10ZV9tUk5BdmFyeWluZykKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKYGBge3J9CiMgbXZ0ZSA9IG1lYW4gb2YgdGhlIHZhcmlhbmNlIGluIHRyYW5zbGF0aW9uIGVmZmljaWVuY3kKY2FsY3VsYXRlX2dlbmVfc3BfbXZ0ZSA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgICAgIAogICAgIyBvdXR2ZWMgaGFzIDI1IGVsZW1lbnRzLiBFYWNoIGVsZW1lbnQgaXMgdGhlIG12dGUgZm9yIHRoZSAxIG1STkFjb25zdGFudCArIDI0IGRpZmZlcmVudCBkYy9yIGNvbWJvcwogICAgb3V0dmVjIDwtIHZlY3RvcigpIAogICAgCiAgICAjIGN1cnJlbnQgZ2VuZSBuYW1lIG91dCBvZiB0aGUgNDgzOSBnZW5lcywgYW5kIGl0cyBpbml0aWFsIG1STkEgbGV2ZWwKICAgIGN1cnJlbnRHZW5lIDwtIGdlbmVOYW1lc1tnZW5lSURdCiAgICBtUk5BYWJ1bmRhbmNlQ3VycmVudEdlbmUgPC0gc2ltSW5wdXRGZWF0dXJlcyRtUk5BYWJ1bmRhbmNlW2dlbmVJRF0KICAgIAogICAgIyBtYXRyaXggdGhhdCBjb250YWlucyBjb3VudEVsbmcgaW5mbyBmb3IgY3VycmVudCBzZWxlY3RlZCBnZW5lCiAgICBjb3VudEVsbmdfbVJOQWNvbnN0YW50IDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUwKGN1cnJlbnRHZW5lLCAiL2dlbmVfc3BfY291bnRFbG5nX3Blck1pbi9tUk5BY29uc3RhbnQiKSkKICAgIHRlX21STkFjb25zdGFudCA8LSBjb3VudEVsbmdfbVJOQWNvbnN0YW50L21STkFhYnVuZGFuY2VDdXJyZW50R2VuZQogICAgIyBnZXQgdmFyaWFuY2UgZm9yIGVhY2ggcm93KHJlcCkgYW5kIHRoZW4gZ2V0IHRoZSBtZWFuIGZvciBhbGwgcmVwcwogICAgbXZ0ZV9tUk5BY29uc3RhbnQgPC0gbWVhbihhcHBseSh0ZV9tUk5BY29uc3RhbnQsIDEsIHZhciwgbmEucm0gPSBUUlVFKSkgIAogICAgb3V0dmVjIDwtIGMob3V0dmVjLCBtdnRlX21STkFjb25zdGFudCkKICAgIAogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlCiAgICBmb3IoaSBpbiAyOm5yb3coZGMuci5kZikpeyAgCiAgICAgICAgY291bnRFbG5nX21STkF2YXJ5aW5nIDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJnZW5lX3NwX2NvdW50RWxuZ19wZXJNaW4iLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgc2VwID0gIi8iKSkKICAgICAgICBtUk5BY291bnRfbVJOQXZhcnlpbmcgPC0gaDVyZWFkKHNpbU91dHB1dEg1LCBwYXN0ZShjdXJyZW50R2VuZSwgImdlbmVfc3BfbVJOQWNvdW50X3Blck1pbiIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCBzZXAgPSAiLyIpKQogICAgICAgICMgdGUgPSB0cmFuc2xhdGlvbiByYXRlCiAgICAgICAgdGVfbVJOQXZhcnlpbmcgPC0gY291bnRFbG5nX21STkF2YXJ5aW5nL21STkFjb3VudF9tUk5BdmFyeWluZyAgIAogICAgICAgICMgY2hhbmdlIGFsbCB0aGUgIkluZiJzIHRvICJOYW4icwogICAgICAgIHRlX21STkF2YXJ5aW5nWyFpcy5maW5pdGUodGVfbVJOQXZhcnlpbmcpXSA8LSBOYU4gCiAgICAgICAgIyBnZXQgdmFyIGZvciBlYWNoIHJvdyhyZXApIGFuZCB0aGVuIGdldCB0aGUgbWVhbiBmb3IgYWxsIHJlcHMKICAgICAgICBtdnRlX21STkF2YXJ5aW5nIDwtIG1lYW4oYXBwbHkodGVfbVJOQXZhcnlpbmcsIDEsIHZhciwgbmEucm0gPSBUUlVFKSkgIAogICAgICAgIG91dHZlYyA8LSBjKG91dHZlYywgbXZ0ZV9tUk5BdmFyeWluZykKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKCgoKYGBge3J9CiMgbW1jID0gbWVhbiBtUk5BIGNvdW50CmNhbGN1bGF0ZV9nZW5lX3NwX21tYyA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgICAKICAgICMgb3V0dmVjIGhhcyAyNSBlbGVtZW50cy4gRWFjaCBlbGVtZW50IGlzIHRoZSBtbWMgZm9yIHRoZSAxIG1STkFjb25zdGFudCArIDI0IGRpZmZlcmVudCBkYy9yIGNvbWJvcwogICAgb3V0dmVjIDwtIHZlY3RvcigpIAogICAgCiAgICAjIGN1cnJlbnQgZ2VuZSBuYW1lIG91dCBvZiB0aGUgNDgzOSBnZW5lcywgIGFuZCBpdHMgaW5pdGlhbCBtUk5BIGxldmVsCiAgICBjdXJyZW50R2VuZSA8LSBnZW5lTmFtZXNbZ2VuZUlEXQogICAgbVJOQWFidW5kYW5jZUN1cnJlbnRHZW5lIDwtIHNpbUlucHV0RmVhdHVyZXMkbVJOQWFidW5kYW5jZVtnZW5lSURdCiAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG1STkFhYnVuZGFuY2VDdXJyZW50R2VuZSkKICAgIAogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlCiAgICBmb3IoaSBpbiAyOm5yb3coZGMuci5kZikpeyAgCiAgICAgICAgbVJOQWNvdW50X21STkF2YXJ5aW5nIDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJnZW5lX3NwX21STkFjb3VudF9wZXJNaW4iLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgc2VwID0gIi8iKSkKICAgICAgICBtbWNfbVJOQXZhcnlpbmcgPC0gbWVhbihtUk5BY291bnRfbVJOQXZhcnlpbmcpCiAgICAgICAgb3V0dmVjIDwtIGMob3V0dmVjLCBtbWNfbVJOQXZhcnlpbmcpCiAgICB9CiAgICAKICAgIGg1Y2xvc2VBbGwoKQogICAgcmV0dXJuKG91dHZlYykKfQpgYGAKCmBgYHtyfQojIG12bWMgPSBtZWFuIG9mIHRoZSB2YXJpYW5jZSBpbiBtUk5BIGNvdW50CmNhbGN1bGF0ZV9nZW5lX3NwX212bWMgPC0gZnVuY3Rpb24oZ2VuZUlELCBzaW1PdXRwdXRINSl7ICAgIAogICAgIyBvdXR2ZWMgaGFzIDI1IGVsZW1lbnRzLiBFYWNoIGVsZW1lbnQgaXMgdGhlIG12bWMgZm9yIHRoZSAxIG1STkFjb25zdGFudCArIDI0IGRpZmZlcmVudCBkYy9yIGNvbWJvcwogICAgb3V0dmVjIDwtIHZlY3RvcigpIAogICAgCiAgICAjIGN1cnJlbnQgZ2VuZSBuYW1lIG91dCBvZiB0aGUgNDgzOSBnZW5lcwogICAgY3VycmVudEdlbmUgPC0gZ2VuZU5hbWVzW2dlbmVJRF0KCiAgICBtdm1jX21STkFjb25zdGFudCA8LSAwICAjIHRoZSB2YXJpYW5jZSBpbiBtUk5BIGNvdW50IGZvciBtUk5BY29uc3RhbnQgaXMgMAogICAgb3V0dmVjIDwtIGMob3V0dmVjLCBtdm1jX21STkFjb25zdGFudCkKICAgIAogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlLCBleGNsdWRpbmcgbVJOQWNvbnN0YW50CiAgICBmb3IoaSBpbiAyOm5yb3coZGMuci5kZikpeyAgCiAgICAgICAgbWNfbVJOQXZhcnlpbmcgPC0gaDVyZWFkKHNpbU91dHB1dEg1LCBwYXN0ZShjdXJyZW50R2VuZSwgImdlbmVfc3BfbVJOQWNvdW50X3Blck1pbiIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCBzZXAgPSAiLyIpKQogICAgICAgICMgZ2V0IHZhcmlhbmNlIGZvciBlYWNoIHJvdyhyZXApIGFuZCB0aGVuIGdldCB0aGUgbWVhbiBmb3IgYWxsIHJlcHMKICAgICAgICBtdm1jX21STkF2YXJ5aW5nIDwtIG1lYW4oYXBwbHkobWNfbVJOQXZhcnlpbmcsIDEsIHZhciwgbmEucm0gPSBUUlVFKSkgIAogICAgICAgIG91dHZlYyA8LSBjKG91dHZlYywgbXZtY19tUk5BdmFyeWluZykKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKYGBge3J9CiMgY3ZtYyA9IGNvZWZmaWNpZW50IHZhcmlhdGlvbiBvZiBtUk5BIGNvdW50CmNhbGN1bGF0ZV9nZW5lX3NwX2N2bWMgPC0gZnVuY3Rpb24oZ2VuZUlELCBzaW1PdXRwdXRINSl7ICAgIAogICAgIyBvdXR2ZWMgaGFzIDI1IGVsZW1lbnRzLiBFYWNoIGVsZW1lbnQgaXMgdGhlIGN2bWMgZm9yIHRoZSAxIG1STkFjb25zdGFudCArIDI0IGRpZmZlcmVudCBkYy9yIGNvbWJvcwogICAgb3V0dmVjIDwtIHZlY3RvcigpIAogICAgCiAgICAjIGN1cnJlbnQgZ2VuZSBuYW1lIG91dCBvZiB0aGUgNDgzOSBnZW5lcywgYW5kIGl0cyBpbml0aWFsIG1STkEgbGV2ZWwKICAgIGN1cnJlbnRHZW5lIDwtIGdlbmVOYW1lc1tnZW5lSURdCiAgICAjIDAgdG8gcmVwcmVzZW50IG1STkFjb25zdGFudAogICAgb3V0dmVjIDwtIGMob3V0dmVjLCAwKQogICAgCiAgICAjIGxvb3AgdGhyb3VnaCB0aGUgZGMvciBwYXJhbWV0ZXIgc3BhY2UsIGV4Y2x1ZGluZyBtUk5BY29uc3RhbnQKICAgIGZvcihpIGluIDI6bnJvdyhkYy5yLmRmKSl7ICAKICAgICAgICBtUk5BY291bnRfbVJOQXZhcnlpbmcgPC0gaDVyZWFkKHNpbU91dHB1dEg1LCBwYXN0ZShjdXJyZW50R2VuZSwgImdlbmVfc3BfbVJOQWNvdW50X3Blck1pbiIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCBzZXAgPSAiLyIpKQogICAgICAgICMgbW1jID0gbWVhbiBtUk5BIGNvdW50CiAgICAgICAgbW1jX21STkF2YXJ5aW5nIDwtIG1lYW4obVJOQWNvdW50X21STkF2YXJ5aW5nKSAKICAgICAgICAjIHNkbWMgPSBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGVhY2ggcm93KHJlcCkgYW5kIHRoZW4gZ2V0IHRoZSBtZWFuIGZvciBhbGwgcmVwcwogICAgICAgIHNkbWNfbVJOQXZhcnlpbmcgPC0gbWVhbihhcHBseShtUk5BY291bnRfbVJOQXZhcnlpbmcsIDEsIHNkLCBuYS5ybSA9IFRSVUUpKSAKICAgICAgICAjIGN2bWMgPSBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24KICAgICAgICBjdm1jX21STkF2YXJ5aW5nIDwtIHNkbWNfbVJOQXZhcnlpbmcvbW1jX21STkF2YXJ5aW5nIAogICAgICAgIG91dHZlYyA8LSBjKG91dHZlYywgY3ZtY19tUk5BdmFyeWluZykKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKYGBge3J9CiMibVJOQV9saWZlVGltZXMiLCAxc3QgbGV2ZWw6IDQ4MzkgZ2VuZXMsIDJuZDogZHR5cGUsIDNyZDogZGMvciBjb21ibyBvciBjdHJsCiMgNHRoOjUwIFggMTAwICggPSA1MDAwIGxpZmUgdGltZSBkYXRhIHBvaW50LCBzb21lIHNwb3RzIHdpbGwgYmUgZmlsbGVkIHdpdGggTkFzIHNpbmNlIG5vdCBhbGwgZ2VuZXMgd291bGQgaGF2ZSBzbyBtYW55IGxpZmUgdGltZXMgY29sbGVjdGVkKSwgdGhlIG1pbmltdW0gZGlzdHJpYnV0aW9uIHNob3VsZCBoYXZlID40MDAgbGlmZSB0aW1lcyBjb2xsZWN0ZWQuCiMgbW1sLSBtZWFuIG1STkEgbGlmZXRpbWVzCmNhbGN1bGF0ZV9nZW5lX3NwX21tbCA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgICAKICAgICMgb3V0dmVjIGhhcyAyNSBlbGVtZW50cy4gRWFjaCBlbGVtZW50IGlzIHRoZSBjdm1jIGZvciB0aGUgMSBtUk5BY29uc3RhbnQgKyAyNCBkaWZmZXJlbnQgZGMvciBjb21ib3MKICAgIG91dHZlYyA8LSB2ZWN0b3IoKSAKICAgIAogICAgIyBjdXJyZW50IGdlbmUgbmFtZSBvdXQgb2YgdGhlIDQ4MzkgZ2VuZXMKICAgIGN1cnJlbnRHZW5lIDwtIGdlbmVOYW1lc1tnZW5lSURdCgogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlCiAgICBmb3IoaSBpbiAxOm5yb3coZGMuci5kZikpeyAgCiAgICAgICAgbWwgPC0gaDVyZWFkKHNpbU91dHB1dEg1LCBwYXN0ZShjdXJyZW50R2VuZSwgIm1STkFfbGlmZVRpbWVzIiwgZGMuci5kZiRwYXJhQ29tYm9baV0sIHNlcCA9ICIvIikpICAKICAgICAgICAjIG1STkEgbGlmZSB0aW1lIGF2ZXJhZ2VkIG92ZXIgc2ltdWxhdGlvbiB0aW1lCiAgICAgICAgbW1sIDwtIG1lYW4obWwsIG5hLnJtID0gVFJVRSkKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG1tbCkKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKYGBge3J9CiMgdm1sLSB2YXJpYW5jZSBpbiBtUk5BIGxpZmV0aW1lcwpjYWxjdWxhdGVfZ2VuZV9zcF92bWwgPC0gZnVuY3Rpb24oZ2VuZUlELHNpbU91dHB1dEg1KXsgICAgCiAgICAjIG91dHZlYyBoYXMgMjUgZWxlbWVudHMuIEVhY2ggZWxlbWVudCBpcyB0aGUgdm1sIGZvciB0aGUgMSBtUk5BY29uc3RhbnQgKyAyNCBkaWZmZXJlbnQgZGMvciBjb21ib3MKICAgIG91dHZlYyA8LSB2ZWN0b3IoKSAKICAgIAogICAgIyBjdXJyZW50IGdlbmUgbmFtZSBvdXQgb2YgdGhlIDQ4MzkgZ2VuZXMKICAgIGN1cnJlbnRHZW5lIDwtIGdlbmVOYW1lc1tnZW5lSURdCgogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlCiAgICBmb3IoaSBpbiAxOm5yb3coZGMuci5kZikpeyAgCiAgICAgICAgbWwgPC0gaDVyZWFkKHNpbU91dHB1dEg1LCBwYXN0ZShjdXJyZW50R2VuZSwgIm1STkFfbGlmZVRpbWVzIiwgZGMuci5kZiRwYXJhQ29tYm9baV0sIHNlcCA9ICIvIikpCiAgICAgICAgIyB2YXJpYW5jZSBpbiBtUk5BIGxpZmUgdGltZSBhbW9uZyA1MDAwIHZhbHVlcyAob3IgbWF5YmUgbGVzcyB0aGFuIDUwMDAgZmlsbGVkIHdpdGggTkFzKQogICAgICAgIHZtbCA8LSB2YXIoYXMubnVtZXJpYyhtbCksIG5hLnJtID0gVFJVRSkgICAKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIHZtbCkKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKYGBge3J9CiMgY3ZtbC0gQ1YgaW4gbVJOQSBsaWZldGltZXMKY2FsY3VsYXRlX2dlbmVfc3BfY3ZtbCA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgICAgCiAgICAjIG91dHZlYyBoYXMgMjUgZWxlbWVudHMuIEVhY2ggZWxlbWVudCBpcyB0aGUgY3ZtbCBmb3IgdGhlIDEgbVJOQWNvbnN0YW50ICsgMjQgZGlmZmVyZW50IGRjL3IgY29tYm9zCiAgICBvdXR2ZWMgPC0gdmVjdG9yKCkgCiAgICAKICAgICMgY3VycmVudCBnZW5lIG5hbWUgb3V0IG9mIHRoZSA0ODM5IGdlbmVzCiAgICBjdXJyZW50R2VuZSA8LSBnZW5lTmFtZXNbZ2VuZUlEXQoKICAgICMgbG9vcCB0aHJvdWdoIHRoZSBkYy9yIHBhcmFtZXRlciBzcGFjZQogICAgZm9yKGkgaW4gMTpucm93KGRjLnIuZGYpKXsgIAogICAgICAgICMgbVJOQSBsaWZldGltZXMgYXZlcmFnZWQgb3ZlciBzaW11bGF0aW9uIHRpbWUKICAgICAgICBtbCA8LSBoNXJlYWQoc2ltT3V0cHV0SDUsIHBhc3RlKGN1cnJlbnRHZW5lLCAibVJOQV9saWZlVGltZXMiLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgc2VwID0gIi8iKSkgIAogICAgICAgIG1tbCA8LSBtZWFuKG1sLCBuYS5ybSA9IFRSVUUpCiAgICAgICAgIyBzZG1sID0gc3RhbmRhcmQgZGV2aWF0aW9uIGluIG1STkEgbGlmZSB0aW1lIGFtb25nIDUwMDAgdmFsdWVzIChvciBtYXliZSBsZXNzIHRoYW4gMTAwMDAgZmlsbGVkIHdpdGggTkFzKQogICAgICAgIHNkbWwgPC0gc2QoYXMubnVtZXJpYyhtbCksIG5hLnJtID0gVFJVRSkgICAKICAgICAgICBjdm1sIDwtIGlmZWxzZShtbWwgIT0gMCwgc2RtbC9tbWwsIDApIAogICAgICAgIG91dHZlYyA8LSBjKG91dHZlYywgY3ZtbCkKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKYGBge3J9CiMgbW1kci0gbWVhbiBtUk5BIGRlY2F5IHJhdGVzCmNhbGN1bGF0ZV9nZW5lX3NwX21tZHIgPC0gZnVuY3Rpb24oZ2VuZUlELCBzaW1PdXRwdXRINSl7ICAgICAKICAgICMgb3V0dmVjIGhhcyAyNSBlbGVtZW50cy4gRWFjaCBlbGVtZW50IGlzIHRoZSBtbWRyIGZvciB0aGUgMSBtUk5BY29uc3RhbnQgKyAyNCBkaWZmZXJlbnQgZGMvciBjb21ib3MKICAgIG91dHZlYyA8LSB2ZWN0b3IoKSAKICAgIAogICAgIyBjdXJyZW50IGdlbmUgbmFtZSBvdXQgb2YgdGhlIDQ4MzkgZ2VuZXMKICAgIGN1cnJlbnRHZW5lIDwtIGdlbmVOYW1lc1tnZW5lSURdCgogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlIAogICAgZm9yKGkgaW4gMTpucm93KGRjLnIuZGYpKXsgIAogICAgICAgICMgbWwgPSBtUk5BIGxpZmUgdGltZSBhdmVyYWdlZCBvdmVyIHNpbXVsYXRpb24gdGltZQogICAgICAgIG1sIDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJtUk5BX2xpZmVUaW1lcyIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCBzZXAgPSAiLyIpKSAgCiAgICAgICAgIyBtbWwgPSBtZWFuIG1STkEgbGlmZSB0aW1lIGF2ZXJhZ2VkIG92ZXIgNTAwMCB2YWx1ZXMgKG9yIG1heWJlIGxlc3MgdGhhbiAxMDAwMCBmaWxsZWQgd2l0aCBOQXMpCiAgICAgICAgbW1sIDwtIG1lYW4obWwsIG5hLnJtID0gVFJVRSkgIAogICAgICAgICMgZGVjYXkgcmF0ZSA9IDEvbWVhbiBsaWZldGltZQogICAgICAgIG1tZHIgPC0gMS9tbWwgCiAgICAgICAgCiAgICAgICAgb3V0dmVjIDwtIGMob3V0dmVjLCBtbWRyKQogICAgfQogICAgCiAgICBoNWNsb3NlQWxsKCkKICAgIHJldHVybihvdXR2ZWMpCn0KYGBgCgpgYGB7cn0KIyJnZW5lX3NwX21STkFtYXJrZWREZWNheV9wZXJNaW4iLCAxc3QgbGV2ZWw6IDQ4MzkgZ2VuZXMsIDJuZDogZHR5cGUsIDNyZDogZGMvciBjb21ibyBvciBtUk5BY29uc3RhbnQsIDR0aDogNTAgcmVwIFggNzIwIG1pbgojIG1tbWQtIG1lYW4gbVJOQXMgbWFya2VkIGZvciBkZWNheSAKY2FsY3VsYXRlX2dlbmVfc3BfbW1tZCA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgICAgCiAgICAjIG91dHZlYyBoYXMgMjUgZWxlbWVudHMuIEVhY2ggZWxlbWVudCBpcyB0aGUgbW1tZCAoIyBvZiBtUk5BIG1hcmtlZCBmb3IgZGVjYXkgYXZlcmFnZWQgb3ZlciBzaW1UaW1lTWluIGFuZCB0ZWNoUmVwcyBmb3IgY2VydGFpbiBnZW5lSUQpIGZvciB0aGUgMSBtUk5BY29uc3RhbnQgKyAyNCBkaWZmZXJlbnQgZGMvciBjb21ib3MKICAgIG91dHZlYyA8LSB2ZWN0b3IoKSAKICAgIAogICAgIyBjdXJyZW50IGdlbmUgbmFtZSBvdXQgb2YgdGhlIDQ4MzkgZ2VuZXMKICAgIGN1cnJlbnRHZW5lIDwtIGdlbmVOYW1lc1tnZW5lSURdCiAgICAKICAgICMgbG9vcCB0aHJvdWdoIHRoZSBkYy9yIHBhcmFtZXRlciBzcGFjZQogICAgZm9yKGkgaW4gMTpucm93KGRjLnIuZGYpKXsgIAogICAgICAgIG1tZCA8LSBoNXJlYWQoc2ltT3V0cHV0SDUsIHBhc3RlKGN1cnJlbnRHZW5lLCAiZ2VuZV9zcF9tUk5BbWFya2VkRGVjYXlfcGVyTWluIiwgZGMuci5kZiRwYXJhQ29tYm9baV0sIHNlcCA9ICIvIikpIAogICAgICAgICMgbWVhbiBtUk5BIG1hcmtlZCBmb3IgZGVjYXkgb3ZlciB0ZWNoIHJlcCBhbmQgc2ltVGltZU1pbgogICAgICAgIG1tbWQgPC0gbWVhbihtbWQpICAKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG1tbWQpCiAgICB9CiAgICAKICAgIGg1Y2xvc2VBbGwoKQogICAgcmV0dXJuKG91dHZlYykKfQpgYGAKCmBgYHtyfQojIG1tYnIgPSAgbWVhbiBtUk5BLWF2ZXJhZ2VkIGJvdW5kIHJpYm9zb21lCmNhbGN1bGF0ZV9nZW5lX3NwX21tYnIgPC0gZnVuY3Rpb24oZ2VuZUlELCBzaW1PdXRwdXRINSl7ICAgIAogICAgIyBvdXR2ZWMgaGFzIDI1IGVsZW1lbnRzLiBFYWNoIGVsZW1lbnQgaXMgdGhlIG1tYnIgZm9yIHRoZSAxIG1STkFjb25zdGFudCArIDI0IGRpZmZlcmVudCBkYy9yIGNvbWJvcwogICAgb3V0dmVjIDwtIHZlY3RvcigpIAogICAgCiAgICAjIGN1cnJlbnQgZ2VuZSBuYW1lIG91dCBvZiB0aGUgNDgzOSBnZW5lcwogICAgY3VycmVudEdlbmUgPC0gZ2VuZU5hbWVzW2dlbmVJRF0KICAgIAogICAgIyBsb29wIHRocm91Z2ggdGhlIGRjL3IgcGFyYW1ldGVyIHNwYWNlCiAgICBmb3IoaSBpbiAxOm5yb3coZGMuci5kZikpeyAgCiAgICAgICAgcmlib2NvdW50IDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJnZW5lX3NwX3RvdEJvdW5kUmlib19wZXJNaW4iLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgc2VwID0gIi8iKSkKICAgICAgICBtUk5BY291bnQgPC0gaDVyZWFkKHNpbU91dHB1dEg1LCBwYXN0ZShjdXJyZW50R2VuZSwgImdlbmVfc3BfbVJOQWNvdW50X3Blck1pbiIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCBzZXAgPSAiLyIpKQogICAgICAgICMgdG90YWwgbnVtYmVyIG9mIGJvdW5kIHJpYm9zIHBlciBnZW5lIHBlciBtaW51dGUgcGVyIHJlcCBub3cgZGl2aWRlZCBieSByZWFsIHRpbWUgbVJOQSBjb3VudAogICAgICAgIG1iciA8LSByaWJvY291bnQvbVJOQWNvdW50IAogICAgICAgICMgY2hhbmdlIGFsbCB0aGUgIkluZiJzIHRvICJOYW4icwogICAgICAgIG1iclshaXMuZmluaXRlKG1icildIDwtIE5hTiAKICAgICAgICAjIG51bWJlciBvZiBib3VuZCByaWJvcyBwZXIgbVJOQSBhdmVyYWdlZCBvdmVyIHRpbWUgYW5kIHRlY2ggcmVwcwogICAgICAgIG1tYnIgPC0gbWVhbihtYnIsIG5hLnJtID0gVFJVRSkgCgogICAgICAgIG91dHZlYyA8LSBjKG91dHZlYywgbW1icikKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKYGBge3J9CiMgbXRiciA9ICBtZWFuIHRvdGFsIGJvdW5kIHJpYm9zb21lICh0b3RhbCA9IGFsbCBtUk5BcyBmb3IgYSBzaW5nbGUgZ2VuZSkKY2FsY3VsYXRlX2dlbmVfc3BfbXRiciA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgICAgCiAgICAjIG91dHZlYyBoYXMgMjUgZWxlbWVudHMuIEVhY2ggZWxlbWVudCBpcyB0aGUgbXRiciBmb3IgdGhlIDEgbVJOQWNvbnN0YW50ICsgMjQgZGlmZmVyZW50IGRjL3IgY29tYm9zCiAgICBvdXR2ZWMgPC0gdmVjdG9yKCkgCiAgICAKICAgICMgY3VycmVudCBnZW5lIG5hbWUgb3V0IG9mIHRoZSA0ODM5IGdlbmVzCiAgICBjdXJyZW50R2VuZSA8LSBnZW5lTmFtZXNbZ2VuZUlEXQogICAgCiAgICAjIGxvb3AgdGhyb3VnaCB0aGUgZGMvciBwYXJhbWV0ZXIgc3BhY2UgCiAgICBmb3IoaSBpbiAxOm5yb3coZGMuci5kZikpeyAgCiAgICAgICAgdGJyIDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJnZW5lX3NwX3RvdEJvdW5kUmlib19wZXJNaW4iLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgc2VwID0gIi8iKSkKICAgICAgICAjIG51bWJlciBvZiB0b3RhbCBib3VuZCByaWJvcyBhdmVyYWdlZCBvdmVyIHRpbWUgYW5kIHRlY2ggcmVwcyBmb3IgZWFjaCBnZW5lCiAgICAgICAgbXRiciA8LSBtZWFuKHRicikKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG10YnIpCiAgICB9CiAgICAKICAgIGg1Y2xvc2VBbGwoKQogICAgcmV0dXJuKG91dHZlYykKfQpgYGAKCmBgYHtyfQojIG12dGJyID0gbWVhbiB2YXJpYW5jZSBpbiB0aGUgdG90YWwgYm91bmQgcmlib3NvbWVzCmNhbGN1bGF0ZV9nZW5lX3NwX212dGJyIDwtIGZ1bmN0aW9uKGdlbmVJRCwgc2ltT3V0cHV0SDUpeyAgICAKICAgICMgb3V0dmVjIGhhcyAyNSBlbGVtZW50cy4gRWFjaCBlbGVtZW50IGlzIHRoZSBtdnRiciBmb3IgdGhlIDEgbVJOQWNvbnN0YW50ICsgMjQgZGlmZmVyZW50IGRjL3IgY29tYm9zCiAgICBvdXR2ZWMgPC0gdmVjdG9yKCkgCiAgICAKICAgICMgY3VycmVudCBnZW5lIG5hbWUgb3V0IG9mIHRoZSA0ODM5IGdlbmVzCiAgICBjdXJyZW50R2VuZSA8LSBnZW5lTmFtZXNbZ2VuZUlEXQogICAgCiAgICAjIGxvb3AgdGhyb3VnaCB0aGUgZGMvciBwYXJhbWV0ZXIgc3BhY2UKICAgIGZvcihpIGluIDE6bnJvdyhkYy5yLmRmKSl7ICAgCiAgICAgICAgdnRiciA8LSBoNXJlYWQoc2ltT3V0cHV0SDUsIHBhc3RlKGN1cnJlbnRHZW5lLCAiZ2VuZV9zcF92YXJpYW5jZUJvdW5kUmlib19wZXJNaW4iLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgc2VwID0gIi8iKSkKICAgICAgICAjIG9mIGJvdW5kIHJpYm9zIHBlciBtUk5BIGF2ZXJhZ2VkIG92ZXIgdGltZSBhbmQgdGVjaCByZXBzCiAgICAgICAgbXZ0YnIgPC0gbWVhbih2dGJyKSAKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG12dGJyKQogICAgfQogICAgCiAgICBoNWNsb3NlQWxsKCkKICAgIHJldHVybihvdXR2ZWMpCn0KYGBgCgoKYGBge3J9CiMgbXR0ID0gbWVhbiB0cmFuc2xhdGlvbiB0aW1lIChhbW9uZyBhbGwgcmlib3NvbWVzIGZvciBhIGdlbmUpCmNhbGN1bGF0ZV9nZW5lX3NwX210dCA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgIAogICAgIyBvdXR2ZWMgaGFzIDI1IGVsZW1lbnRzLiBFYWNoIGVsZW1lbnQgaXMgdGhlIG10dCBmb3IgdGhlIDEgbVJOQWNvbnN0YW50ICsgMjQgZGlmZmVyZW50IGRjL3IgY29tYm9zCiAgICBvdXR2ZWMgPC0gdmVjdG9yKCkKICAgIAogICAgIyBjdXJyZW50IGdlbmUgbmFtZSBvdXQgb2YgdGhlIDQ4MzkgZ2VuZXMKICAgIGN1cnJlbnRHZW5lIDwtIGdlbmVOYW1lc1tnZW5lSURdCiAgICAKICAgICMgbG9vcCB0aHJvdWdoIHRoZSBkYy9yIHBhcmFtZXRlciBzcGFjZQogICAgZm9yKGkgaW4gMTpucm93KGRjLnIuZGYpKXsKICAgICAgICAjIGF0dCA9IGF2ZXJhZ2UgdHJhbnNsYXRpb24gdGltZSBhbW9uZyBhbGwgdGhlIHJpYm9zCiAgICAgICAgYXR0IDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJnZW5lX3RvdGV0aW1lcyIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCBzZXAgPSAiLyIpKVssIDJdIAogICAgICAgIG10dCA8LSBtZWFuKGF0dCkKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG10dCkKICAgIH0KICAgIAogICAgaDVjbG9zZUFsbCgpCiAgICByZXR1cm4ob3V0dmVjKQp9CmBgYAoKYGBge3J9CiMgbXZ0dCA9IG1lYW4gb2YgdmFyaWFuY2UgaW4gdHJhbnNsYXRpb24gdGltZSAodmFyIGFtb25nIGFsbCByaWJvc29tZXMgZm9yIGEgZ2VuZSkKY2FsY3VsYXRlX2dlbmVfc3BfbXZ0dCA8LSBmdW5jdGlvbihnZW5lSUQsIHNpbU91dHB1dEg1KXsgIAogICAgIyBvdXR2ZWMgaGFzIDI1IGVsZW1lbnRzLiBFYWNoIGVsZW1lbnQgaXMgdGhlIG12dHQgZm9yIHRoZSAxIG1STkFjb25zdGFudCArIDI0IGRpZmZlcmVudCBkYy9yIGNvbWJvcwogICAgb3V0dmVjIDwtIHZlY3RvcigpCiAgICAKICAgICMgY3VycmVudCBnZW5lIG5hbWUgb3V0IG9mIHRoZSA0ODM5IGdlbmVzCiAgICBjdXJyZW50R2VuZSA8LSBnZW5lTmFtZXNbZ2VuZUlEXQogICAgCiAgICAjIGxvb3AgdGhyb3VnaCB0aGUgZGMvciBwYXJhbWV0ZXIgc3BhY2UKICAgIGZvcihpIGluIDE6bnJvdyhkYy5yLmRmKSl7IAogICAgICAgICMgdnR0ID0gdmFyaWFuY2UgaW4gdHJhbnNsYXRpb24gdGltZSBhbW9uZyBhbGwgdGhlIHJpYm9zCiAgICAgICAgdnR0IDwtIGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoY3VycmVudEdlbmUsICJnZW5lX3RvdGV0aW1lcyIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCBzZXAgPSAiLyIpKVssIDNdCiAgICAgICAgbXZ0dCA8LSBtZWFuKHZ0dCkKICAgICAgICBvdXR2ZWMgPC0gYyhvdXR2ZWMsIG12dHQpCiAgICB9CiAgICAKICAgIGg1Y2xvc2VBbGwoKQogICAgcmV0dXJuKG91dHZlYykKfQpgYGAKCgoKCiMhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhIERPTidUIFJVTiBGT0xMT1dJTkcgQ0hVTktTIFVOTEVTUyBUSEUgRkVBVEhFUiBGSUxFUyBET04nVCBBTFJFQURZIEVYSVNUCiMjIyBUaGUgZm9sbG93aW5nIGNodW5rcyB1dGlsemllIG11bHRpdGhyZWFkaW5nLCBtYWtlIHN1cmUgdGhlIG1jLmNvcmVzIGFyZSBzZXQgdG8gYXBwcm9wZXJpYXRlIG51bWJlcnMuCmBgYHtyfQpwcmludChTeXMudGltZSgpKQptcHNyTGlzdCA8LSBtY2xhcHBseSgxOjQ4MzksIGZ1bmN0aW9uKHgpe2NhbGN1bGF0ZV9nZW5lX3NwX21wc3IoZ2VuZUlEID0geCwgc2ltT3V0cHV0SDUgPSBzaW1PdXRwdXRINSl9LCBtYy5jb3JlcyA9IDQ1KQojIHRvb2sgMm1pbiB0byBydW4KcHJpbnQoU3lzLnRpbWUoKSkKCiMgbmNvbCA9IDI1LCBucm93ID0gNDgzOQptcHNyQWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUoZG8uY2FsbChyYmluZCwgbXBzckxpc3QpKQoKd3JpdGVfZmVhdGhlcihtcHNyQWxsZ2VuZUFsbGRjciwgcGF0aCA9ICIuLi9jYWxjdWxhdGVkTWV0cmljcy9tcHNyQWxsZ2VuZUFsbGRjci5mZWF0aGVyIikKYGBgCgpgYGB7cn0KcHJpbnQoU3lzLnRpbWUoKSkKbXZwc0xpc3QgPC0gbWNsYXBwbHkoMTo0ODM5LCBmdW5jdGlvbih4KXtjYWxjdWxhdGVfZ2VuZV9zcF9tdnBzKGdlbmVJRCA9IHgsIHNpbU91dHB1dEg1PSBzaW1PdXRwdXRINSl9LCBtYy5jb3JlcyA9IDQ1KQojIHRvb2sgMm1pbiB0byBydW4KcHJpbnQoU3lzLnRpbWUoKSkKCgojIG5jb2wgPSAyNSwgbnJvdyA9IDQ4MzkKbXZwc0FsbGdlbmVBbGxkY3IgPC0gYXNfdGliYmxlKGRvLmNhbGwocmJpbmQsIG12cHNMaXN0KSkKCndyaXRlX2ZlYXRoZXIobXZwc0FsbGdlbmVBbGxkY3IsIHBhdGggPSAiLi4vY2FsY3VsYXRlZE1ldHJpY3MvbXZwc0FsbGdlbmVBbGxkY3IuZmVhdGhlciIpCmBgYAoKYGBge3J9CnByaW50KFN5cy50aW1lKCkpCmN2cHNMaXN0IDwtIG1jbGFwcGx5KDE6NDgzOSwgZnVuY3Rpb24oeCl7Y2FsY3VsYXRlX2dlbmVfc3BfY3ZwcyhnZW5lSUQgPSB4LCBzaW1PdXRwdXRINSA9IHNpbU91dHB1dEg1KX0sIG1jLmNvcmVzID0gNDUpCiMgMTI6NDQgYmVnYW4gMTI6NDkgZmluaXNoCnByaW50KFN5cy50aW1lKCkpCgojIG5jb2wgPSAyNSwgbnJvdyA9IDQ4MzkKY3Zwc0FsbGdlbmVBbGxkY3IgPC0gYXNfdGliYmxlKGRvLmNhbGwocmJpbmQsIGN2cHNMaXN0KSkKCndyaXRlX2ZlYXRoZXIoY3Zwc0FsbGdlbmVBbGxkY3IsIHBhdGggPSAiLi4vY2FsY3VsYXRlZE1ldHJpY3MvY3Zwc0FsbGdlbmVBbGxkY3IuZmVhdGhlciIpCmBgYAoKYGBge3J9CnByaW50KFN5cy50aW1lKCkpCmNwc3JMaXN0IDwtIG1jbGFwcGx5KDE6bnJvdyhkYy5yLmRmKSwgZnVuY3Rpb24oeCl7Y2FsY3VsYXRlX3BhcmFfc3BfY3BzcihwaWQgPSB4KX0sIG1jLmNvcmVzID0gNDUpCiNwYXJhbWV0ZXIgaWQsIDE6MjUsIDEgPSBtUk5BY29uc3RhbnQsIDI6MjUgPSBkaWZmZXJlbnQgZGMvciBjb21ib3MKIyB0b29rIDJtaW4KcHJpbnQoU3lzLnRpbWUoKSkKCgojIGdldCB0aGUgY3BzciAoY2VsbHVsYXIgcHJvdGVpbiBzeW5ldGhlc2lzIHJhdGVzKSBvZiA1MCB0ZWNoIHJlcHMgZm9yIGFsbCB0aGUgcGFyYW1ldGVyIGNvbWJvcwpjcHNyQWxsZGNyQWxscmVwIDwtIGFzX3RpYmJsZSh0KGRhdGEuZnJhbWUoZG8uY2FsbChyYmluZCwgY3Bzckxpc3QpKSkpICAjIG5jb2w9MjUgcGlkLCBucm93PTUwIHRlY2ggcmVwcwpjb2xuYW1lcyhjcHNyQWxsZGNyQWxscmVwKSA8LSBkYy5yLmRmJHBhcmFDb21ibwoKd3JpdGVfZmVhdGhlcihjcHNyQWxsZGNyQWxscmVwLCBwYXRoID0gIi4uL2NhbGN1bGF0ZWRNZXRyaWNzL2Nwc3JBbGxkY3JBbGxyZXAuZmVhdGhlciIpCgpgYGAKCmBgYHtyfQpwcmludChTeXMudGltZSgpKQojIHBpZCA9IHBhcmFtZXRlciBpZCA9IDE6MjUsIDEgPSBtUk5BY29uc3RhbnQsIDI6MjUgPSBkaWZmZXJlbnQgZGMvciBjb21ib3MsIG91dHB1dCBpcyBhIG51bWJlcgptY3Bzckxpc3QgPC0gbWNsYXBwbHkoMTpucm93KGRjLnIuZGYpLCBmdW5jdGlvbih4KXtjYWxjdWxhdGVfcGFyYV9zcF9tY3BzcihwaWQgPSB4KX0sIG1jLmNvcmVzID0gNDUpCiMgdG9vayAybWluCnByaW50KFN5cy50aW1lKCkpCgojIG1jcHNyQWxsZGNyIGlzIGEgdmVjdG9yIG9mIDI1IG51bWJlcnMKbWNwc3JBbGxkY3IgPC0gYXNfdGliYmxlKGRhdGEuZnJhbWUoTUNQU1IgPSB1bmxpc3QobWNwc3JMaXN0KSwKICAgICAgICAgICAgICAgICAgICAgICBwYXJhSUQgPSBkYy5yLmRmJHBhcmFJRCkpCgp3cml0ZV9mZWF0aGVyKG1jcHNyQWxsZGNyLCBwYXRoID0gIi4uL2NhbGN1bGF0ZWRNZXRyaWNzL21jcHNyQWxsZGNyLmZlYXRoZXIiKQpgYGAKCmBgYHtyfQpwcmludChTeXMudGltZSgpKQptdGVMaXN0IDwtIG1jbGFwcGx5KDE6NDgzOSwgZnVuY3Rpb24oeCl7Y2FsY3VsYXRlX2dlbmVfc3BfbXRlKGdlbmVJRCA9IHgsIHNpbU91dHB1dEg1ID0gc2ltT3V0cHV0SDUpfSwgbWMuY29yZXMgPSA0NSkKcHJpbnQoU3lzLnRpbWUoKSkKCiMgbmNvbCA9IDI1LCBucm93ID0gNDgzOQptdGVBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZShkby5jYWxsKHJiaW5kLCBtdGVMaXN0KSkKCndyaXRlX2ZlYXRoZXIobXRlQWxsZ2VuZUFsbGRjciwgcGF0aCA9ICIuLi9jYWxjdWxhdGVkTWV0cmljcy9tdGVBbGxnZW5lQWxsZGNyLmZlYXRoZXIiKQpgYGAKCmBgYHtyfQpwcmludChTeXMudGltZSgpKQptdnRlTGlzdCA8LSBtY2xhcHBseSgxOjQ4MzksIGZ1bmN0aW9uKHgpe2NhbGN1bGF0ZV9nZW5lX3NwX212dGUoZ2VuZUlEID0geCwgc2ltT3V0cHV0SDUgPSBzaW1PdXRwdXRINSl9LCBtYy5jb3JlcyA9IDQ1KQojIHRvb2sgMyBtaW4KcHJpbnQoU3lzLnRpbWUoKSkKCiMgbmNvbCA9IDI1LCBucm93ID0gNDgzOQptdnRlQWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUoZG8uY2FsbChyYmluZCwgbXZ0ZUxpc3QpKQoKd3JpdGVfZmVhdGhlcihtdnRlQWxsZ2VuZUFsbGRjciwgcGF0aCA9ICIuLi9jYWxjdWxhdGVkTWV0cmljcy9tdnRlQWxsZ2VuZUFsbGRjci5mZWF0aGVyIikKYGBgCgpgYGB7cn0KcHJpbnQoU3lzLnRpbWUoKSkKbW1jTGlzdCA8LSBtY2xhcHBseSgxOjQ4MzksIGZ1bmN0aW9uKHgpe2NhbGN1bGF0ZV9nZW5lX3NwX21tYyhnZW5lSUQgPSB4LCBzaW1PdXRwdXRINSA9IHNpbU91dHB1dEg1KX0sIG1jLmNvcmVzID0gNDUpCiMgdG9vayAybWluIHRvIHJ1bgpwcmludChTeXMudGltZSgpKQoKIyBuY29sID0gMjUsIG5yb3cgPSA0ODM5Cm1tY0FsbGdlbmVBbGxkY3IgPC0gYXNfdGliYmxlKGRvLmNhbGwocmJpbmQsIG1tY0xpc3QpKQoKd3JpdGVfZmVhdGhlcihtbWNBbGxnZW5lQWxsZGNyLCBwYXRoID0gIi4uL2NhbGN1bGF0ZWRNZXRyaWNzL21tY0FsbGdlbmVBbGxkY3IuZmVhdGhlciIpCmBgYAoKYGBge3J9CnByaW50KFN5cy50aW1lKCkpCm12bWNMaXN0IDwtIG1jbGFwcGx5KDE6NDgzOSwgZnVuY3Rpb24oeCl7Y2FsY3VsYXRlX2dlbmVfc3BfbXZtYyhnZW5lSUQgPSB4LCBzaW1PdXRwdXRINSA9IHNpbU91dHB1dEg1KX0sIG1jLmNvcmVzID0gNDUpCiMgdG9vayAybWluIHRvIHJ1bgpwcmludChTeXMudGltZSgpKQoKIyBuY29sID0gMjUsIG5yb3cgPSA0ODM5Cm12bWNBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZShkby5jYWxsKHJiaW5kLCBtdm1jTGlzdCkpCgp3cml0ZV9mZWF0aGVyKG12bWNBbGxnZW5lQWxsZGNyLCBwYXRoID0gIi4uL2NhbGN1bGF0ZWRNZXRyaWNzL212bWNBbGxnZW5lQWxsZGNyLmZlYXRoZXIiKQpgYGAKCmBgYHtyfQpwcmludChTeXMudGltZSgpKQpjdm1jTGlzdCA8LSBtY2xhcHBseSgxOjQ4MzksIGZ1bmN0aW9uKHgpe2NhbGN1bGF0ZV9nZW5lX3NwX2N2bWMoZ2VuZUlEID0geCwgc2ltT3V0cHV0SDUgPSBzaW1PdXRwdXRINSl9LCBtYy5jb3JlcyA9IDQ1KQojIDEyOjQ0IGJlZ2FuIDEyOjQ5IGZpbmlzaApwcmludChTeXMudGltZSgpKQoKIyBuY29sID0gMjUsIG5yb3cgPSA0ODM5CmN2bWNBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZShkby5jYWxsKHJiaW5kLCBjdm1jTGlzdCkpCgp3cml0ZV9mZWF0aGVyKGN2bWNBbGxnZW5lQWxsZGNyLCBwYXRoID0gIi4uL2NhbGN1bGF0ZWRNZXRyaWNzL2N2bWNBbGxnZW5lQWxsZGNyLmZlYXRoZXIiKQpgYGAKCmBgYHtyfQpwcmludChTeXMudGltZSgpKQptbWxMaXN0IDwtIG1jbGFwcGx5KDE6NDgzOSwgZnVuY3Rpb24oeCl7Y2FsY3VsYXRlX2dlbmVfc3BfbW1sKGdlbmVJRCA9IHgsIHNpbU91dHB1dEg1ID0gc2ltT3V0cHV0SDUpfSwgbWMuY29yZXMgPSA0NSkKIyB0b29rIDJtaW4gdG8gcnVuCnByaW50KFN5cy50aW1lKCkpCgojIG5jb2wgPSAyNSwgbnJvdyA9IDQ4MzkKbW1sQWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUoZG8uY2FsbChyYmluZCwgbW1sTGlzdCkpCgp3cml0ZV9mZWF0aGVyKG1tbEFsbGdlbmVBbGxkY3IsIHBhdGggPSAiLi4vY2FsY3VsYXRlZE1ldHJpY3MvbW1sQWxsZ2VuZUFsbGRjci5mZWF0aGVyIikKYGBgCgpgYGB7cn0KcHJpbnQoU3lzLnRpbWUoKSkKdm1sTGlzdCA8LSBtY2xhcHBseSgxOjQ4MzksIGZ1bmN0aW9uKHgpe2NhbGN1bGF0ZV9nZW5lX3NwX3ZtbChnZW5lSUQgPSB4LCBzaW1PdXRwdXRINSA9IHNpbU91dHB1dEg1KX0sIG1jLmNvcmVzID0gNDUpCiMgdG9vayAybWluIHRvIHJ1bgpwcmludChTeXMudGltZSgpKQoKIyBuY29sID0gMjUsIG5yb3cgPSA0ODM5CnZtbEFsbGdlbmVBbGxkY3IgPC0gYXNfdGliYmxlKGRvLmNhbGwocmJpbmQsIHZtbExpc3QpKQoKd3JpdGVfZmVhdGhlcih2bWxBbGxnZW5lQWxsZGNyLCBwYXRoID0gIi4uL2NhbGN1bGF0ZWRNZXRyaWNzL3ZtbEFsbGdlbmVBbGxkY3IuZmVhdGhlciIpCmBgYAoKYGBge3J9CnByaW50KFN5cy50aW1lKCkpCmN2bWxMaXN0IDwtIG1jbGFwcGx5KDE6NDgzOSwgZnVuY3Rpb24oeCl7Y2FsY3VsYXRlX2dlbmVfc3BfY3ZtbChnZW5lSUQgPSB4LCBzaW1PdXRwdXRINSA9IHNpbU91dHB1dEg1KX0sIG1jLmNvcmVzID0gNDUpCiMgdG9vayAybWluIHRvIHJ1bgpwcmludChTeXMudGltZSgpKQoKIyBuY29sID0gMjUsIG5yb3cgPSA0ODM5CmN2bWxBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZShkby5jYWxsKHJiaW5kLCBjdm1sTGlzdCkpCgp3cml0ZV9mZWF0aGVyKGN2bWxBbGxnZW5lQWxsZGNyLCBwYXRoID0gIi4uL2NhbGN1bGF0ZWRNZXRyaWNzL2N2bWxBbGxnZW5lQWxsZGNyLmZlYXRoZXIiKQpgYGAKCmBgYHtyfQpwcmludChTeXMudGltZSgpKQptbWRyTGlzdCA8LSBtY2xhcHBseSgxOjQ4MzksIGZ1bmN0aW9uKHgpe2NhbGN1bGF0ZV9nZW5lX3NwX21tZHIoZ2VuZUlEID0geCwgc2ltT3V0cHV0SDUgPSBzaW1PdXRwdXRINSl9LCBtYy5jb3JlcyA9IDQ1KQojIHRvb2sgMm1pbiB0byBydW4KcHJpbnQoU3lzLnRpbWUoKSkKCiMgbmNvbCA9IDI1LCBucm93ID0gNDgzOQptbWRyQWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUoZG8uY2FsbChyYmluZCwgbW1kckxpc3QpKQoKd3JpdGVfZmVhdGhlcihtbWRyQWxsZ2VuZUFsbGRjciwgcGF0aCA9ICIuLi9jYWxjdWxhdGVkTWV0cmljcy9tbWRyQWxsZ2VuZUFsbGRjci5mZWF0aGVyIikKYGBgCgpgYGB7cn0KcHJpbnQoU3lzLnRpbWUoKSkKbW1tZExpc3QgPC0gbWNsYXBwbHkoMTo0ODM5LCBmdW5jdGlvbih4KXtjYWxjdWxhdGVfZ2VuZV9zcF9tbW1kKGdlbmVJRCA9IHgsIHNpbU91dHB1dEg1ID0gc2ltT3V0cHV0SDUpfSwgbWMuY29yZXMgPSA0NSkKIyB0b29rIDMgbWluCnByaW50KFN5cy50aW1lKCkpCgojIG5jb2wgPSAyNSwgbnJvdyA9IDQ4MzkKbW1tZEFsbGdlbmVBbGxkY3IgPC0gYXNfdGliYmxlKGRvLmNhbGwocmJpbmQsIG1tbWRMaXN0KSkKCndyaXRlX2ZlYXRoZXIobW1tZEFsbGdlbmVBbGxkY3IsIHBhdGggPSAiLi4vY2FsY3VsYXRlZE1ldHJpY3MvbW1tZEFsbGdlbmVBbGxkY3IuZmVhdGhlciIpCmBgYAoKYGBge3J9CnByaW50KFN5cy50aW1lKCkpCm1tYnJMaXN0IDwtIG1jbGFwcGx5KDE6NDgzOSwgZnVuY3Rpb24oeCl7Y2FsY3VsYXRlX2dlbmVfc3BfbW1icihnZW5lSUQgPSB4LCBzaW1PdXRwdXRINSA9IHNpbU91dHB1dEg1KX0sIG1jLmNvcmVzID0gNDUpCiMgdG9vayAybWluIHRvIHJ1bgpwcmludChTeXMudGltZSgpKQoKIyBuY29sID0gMjUsIG5yb3cgPSA0ODM5Cm1tYnJBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZShkby5jYWxsKHJiaW5kLCBtbWJyTGlzdCkpCgp3cml0ZV9mZWF0aGVyKG1tYnJBbGxnZW5lQWxsZGNyLCBwYXRoID0gIi4uL2NhbGN1bGF0ZWRNZXRyaWNzL21tYnJBbGxnZW5lQWxsZGNyLmZlYXRoZXIiKQpgYGAKCmBgYHtyfQpwcmludChTeXMudGltZSgpKQptdGJyTGlzdCA8LSBtY2xhcHBseSgxOjQ4MzksIGZ1bmN0aW9uKHgpe2NhbGN1bGF0ZV9nZW5lX3NwX210YnIoZ2VuZUlEID0geCwgc2ltT3V0cHV0SDUgPSBzaW1PdXRwdXRINSl9LCBtYy5jb3JlcyA9IDQ1KQojIHRvb2sgMm1pbiB0byBydW4KcHJpbnQoU3lzLnRpbWUoKSkKCiMgbmNvbCA9IDI1LCBucm93ID0gNDgzOQptdGJyQWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUoZG8uY2FsbChyYmluZCwgbXRickxpc3QpKQoKd3JpdGVfZmVhdGhlcihtdGJyQWxsZ2VuZUFsbGRjciwgcGF0aCA9ICIuLi9jYWxjdWxhdGVkTWV0cmljcy9tdGJyQWxsZ2VuZUFsbGRjci5mZWF0aGVyIikKYGBgCgpgYGB7cn0KcHJpbnQoU3lzLnRpbWUoKSkKbXZ0YnJMaXN0IDwtIG1jbGFwcGx5KDE6NDgzOSwgZnVuY3Rpb24oeCl7Y2FsY3VsYXRlX2dlbmVfc3BfbXZ0YnIoZ2VuZUlEID0geCwgc2ltT3V0cHV0SDUgPSBzaW1PdXRwdXRINSl9LCBtYy5jb3JlcyA9IDQ1KQojIHRvb2sgMm1pbiB0byBydW4KcHJpbnQoU3lzLnRpbWUoKSkKCiMgbmNvbCA9IDI1LCBucm93ID0gNDgzOQptdnRickFsbGdlbmVBbGxkY3IgPC0gYXNfdGliYmxlKGRvLmNhbGwocmJpbmQsIG12dGJyTGlzdCkpCgp3cml0ZV9mZWF0aGVyKG12dGJyQWxsZ2VuZUFsbGRjciwgcGF0aCA9ICIuLi9jYWxjdWxhdGVkTWV0cmljcy9tdnRickFsbGdlbmVBbGxkY3IuZmVhdGhlciIpCmBgYAoKCmBgYHtyfQpwcmludChTeXMudGltZSgpKQptdHRMaXN0IDwtIG1jbGFwcGx5KDE6NDgzOSwgZnVuY3Rpb24oeCl7Y2FsY3VsYXRlX2dlbmVfc3BfbXR0KGdlbmVJRCA9IHgsIHNpbU91dHB1dEg1ID0gc2ltT3V0cHV0SDUpfSwgbWMuY29yZXMgPSA0NSkKIyB0b29rIDJtaW4gdG8gcnVuCnByaW50KFN5cy50aW1lKCkpCgojIG5jb2wgPSAyNSwgbnJvdyA9IDQ4MzkKbXR0QWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUoZG8uY2FsbChyYmluZCwgbXR0TGlzdCkpCgp3cml0ZV9mZWF0aGVyKG10dEFsbGdlbmVBbGxkY3IsIHBhdGggPSAiLi4vY2FsY3VsYXRlZE1ldHJpY3MvbXR0QWxsZ2VuZUFsbGRjci5mZWF0aGVyIikKCmBgYAoKCmBgYHtyfQpwcmludChTeXMudGltZSgpKQptdnR0TGlzdCA8LSBtY2xhcHBseSgxOjQ4MzksIGZ1bmN0aW9uKHgpe2NhbGN1bGF0ZV9nZW5lX3NwX212dHQoZ2VuZUlEID0geCwgc2ltT3V0cHV0SDUgPSBzaW1PdXRwdXRINSl9LCBtYy5jb3JlcyA9IDQ1KQojIHRvb2sgMm1pbiB0byBydW4KcHJpbnQoU3lzLnRpbWUoKSkKCiMgbmNvbCA9IDI1LCBucm93ID0gNDgzOQptdnR0QWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUoZG8uY2FsbChyYmluZCwgbXZ0dExpc3QpKQoKd3JpdGVfZmVhdGhlcihtdnR0QWxsZ2VuZUFsbGRjciwgcGF0aCA9ICIuLi9jYWxjdWxhdGVkTWV0cmljcy9tdnR0QWxsZ2VuZUFsbGRjci5mZWF0aGVyIikKCmBgYAoKIyBjYWxjdWxhdGluZyB0aGUgbWVhbiBudW1iZXIgb2YgZnJlZSByaWJvcyAoYXZlcmFnZWQgb3ZlciBzaW1UaW1lTWluIGFuZCB0ZWNoUmVwcykgZm9yIGFsbCBkYy5yLmNvbWJvcwpgYGB7cn0KIyBNRlIgPSBtZWFuIGZyZWUgcmlibwojIFJNRlIgPSByZWxhdGl2ZSBtZWFuIGZyZWUgcmlibwptZnIgPC0gYygpIAojIGxvb3AgdGhyb3VnaCB0aGUgZGMvciBwYXJhbWV0ZXIgc3BhY2UKZm9yKGkgaW4gMTpucm93KGRjLnIuZGYpKXsgCiAgICAjIGZyZWVfcmlibyBhdmVyYWdlZCBieSBzaW1UaW1lTWluIGFuZCB0ZWNoUmVwcwogICAgbWZyIDwtIGMobWZyLCBtZWFuKGg1cmVhZChzaW1PdXRwdXRINSwgcGFzdGUoImZyZWVfcmlib190Uk5BX3Blck1pbiIsIGRjLnIuZGYkcGFyYUNvbWJvW2ldLCAicmlibyIsIHNlcCA9ICIvIikpLCBuYS5ybSA9IFRSVUUpKQp9CgpybWZyIDwtIG1mci9tZnJbMV0Kcm1mcl9kZiA8LSBhc190aWJibGUoZGF0YS5mcmFtZShSTUZSID0gcm1mciwKICAgICAgICAgICAgICAgICAgICAgIE1GUiA9IG1mciwKICAgICAgICAgICAgICAgICAgICAgIHBhcmFJRCA9IGRjLnIuZGYkcGFyYUlEKSkKCmBgYAoKCiMgZ2V0dGluZyBhbGwgaW5wdXQgZmVhdHVyZXMgYW5kIG91dHB1dCByZXN1bHRzIHRvZ2V0aGVyIGluIGFsbFNpbUlucHV0T3V0cHV0CmBgYHtyfQojIGNvbnZlcnQgYW55IGlucHV0IGRhdGFmcmFtZXMgKGUuZy4gbXRlQWxsZ2VuZUFsbGRjcikgdG8gbG9uZyBmb3JtYXQKZGYuY29udmVydC5mdW4gPC0gZnVuY3Rpb24oeCl7ICAgCiAgICBpbnB1dGRmID0gY2FsY3VsYXRlZE1ldHJpY3MubGlzdFtbeF1dCiAgICBkZm5hbWUgPSBzdHJfc3ViKHRvdXBwZXIobmFtZXMoY2FsY3VsYXRlZE1ldHJpY3MubGlzdClbW3hdXSksIDEsIC0xNCkKCiAgICBpbnB1dGRmICU+JQogICAgICAgIG11dGF0ZShPUkYgPSBzaW1JbnB1dEZlYXR1cmVzJE9SRikgJT4lCiAgICAgICAgZ2F0aGVyXyhrZXlfY29sID0gInBhcmFJRCIsIHZhbHVlX2NvbCA9IGRmbmFtZSwgZ2F0aGVyX2NvbHMgPSBjb2xuYW1lcyhpbnB1dGRmKVsxOm5yb3coZGMuci5kZildKQp9CgojIFJlYWQgaW4gdGhlIGZpbGVzIHRoYXQgY29uYXRpbnMgIkFsbGdlbmVBbGxkY3IuZmVhdGhlciIsIHRoZXNlIGZpbGVzIGNhbiBiZSBsZWZ0X2pvaW5lZCBieSAicGFyYUlEIiBhbmQgIk9SRiIKZmlsZXMubG9jcyA8LSBkaXIoIi4uL2NhbGN1bGF0ZWRNZXRyaWNzIiwgcGF0dGVybiA9ICJBbGxnZW5lQWxsZGNyLmZlYXRoZXIiLCBmdWxsLm5hbWVzID0gVFJVRSkKCiMgcmVhZF9mZWF0aGVyIGZvciBhbGwgdGhlIGZpbGVzIGluIHRoaXMgbG9jYXRpb24KY2FsY3VsYXRlZE1ldHJpY3MubGlzdCA8LSBzYXBwbHkoZmlsZXMubG9jcywgcmVhZF9mZWF0aGVyLCBzaW1wbGlmeSA9IEZBTFNFKSAgCiMgZXhjbHVkZSB0aGUgcGF0aCBhbmQgb25seSBleHRyYWN0IHRoZSBkYXRhIGZyYW1lIG5hbWVzLCBlLmcuICJtbWNBbGxnZW5lQWxsZGNyIgpuYW1lcyhjYWxjdWxhdGVkTWV0cmljcy5saXN0KSA8LSBzdHJfc3ViKG5hbWVzKGNhbGN1bGF0ZWRNZXRyaWNzLmxpc3QpLCBuY2hhcigiLi4vY2FsY3VsYXRlZE1ldHJpY3MvIikrMSwgLTkpICAgCgoKIyBkaXZpZGUgbXRlIG9mIDI1IGRjL3IgY29tYm8gYnkgbXRlIG9mIHRoZSBtUk5BY29uc3RhbnQgPSBybXRlLCByZWxhdGl2ZSBtZWFuIHRyYW5zbGF0aW9uIGVmZmljaWVuY3kKIyBYMSA9IG1STkEgY29uc3RhbnQsIFgyOlgyNSA9IG1STkF2YXJ5aW5nCiMgZGltKHJtdGVBbGxnZW5lQWxsZGNyKSA9IDQ4MzkgWCAyNQpjYWxjdWxhdGVkTWV0cmljcy5saXN0JHJtcHNyQWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUodChhcHBseShjYWxjdWxhdGVkTWV0cmljcy5saXN0JG1wc3JBbGxnZW5lQWxsZGNyLCAxLCBmdW5jdGlvbih4KXt4WzE6bnJvdyhkYy5yLmRmKV0veFsxXX0pKSkKY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRybXZwc0FsbGdlbmVBbGxkY3IgPC0gYXNfdGliYmxlKHQoYXBwbHkoY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRtdnBzQWxsZ2VuZUFsbGRjciwgMSwgZnVuY3Rpb24oeCl7eFsxOm5yb3coZGMuci5kZildL3hbMV19KSkpCmNhbGN1bGF0ZWRNZXRyaWNzLmxpc3QkcmN2cHNBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZSh0KGFwcGx5KGNhbGN1bGF0ZWRNZXRyaWNzLmxpc3QkY3Zwc0FsbGdlbmVBbGxkY3IsIDEsIGZ1bmN0aW9uKHgpe3hbMTpucm93KGRjLnIuZGYpXS94WzFdfSkpKSAjeFsxXSBpcyBmb3IgbVJOQWNvbnN0YW50CmNhbGN1bGF0ZWRNZXRyaWNzLmxpc3Qkcm10ZUFsbGdlbmVBbGxkY3IgPC0gIGFzX3RpYmJsZSh0KGFwcGx5KGNhbGN1bGF0ZWRNZXRyaWNzLmxpc3QkbXRlQWxsZ2VuZUFsbGRjciwgMSwgZnVuY3Rpb24oeCl7eFsxOm5yb3coZGMuci5kZildL3hbMV19KSkpICN4WzFdIGlzIGZvciBtUk5BY29uc3RhbnQKY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRybXZ0ZUFsbGdlbmVBbGxkY3IgPC0gYXNfdGliYmxlKHQoYXBwbHkoY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRtdnRlQWxsZ2VuZUFsbGRjciwgMSwgZnVuY3Rpb24oeCl7eFsxOm5yb3coZGMuci5kZildL3hbMV19KSkpCmNhbGN1bGF0ZWRNZXRyaWNzLmxpc3QkY3ZtY0FsbGdlbmVBbGxkY3IgPC0gc3FydChjYWxjdWxhdGVkTWV0cmljcy5saXN0JG12bWNBbGxnZW5lQWxsZGNyKS9jYWxjdWxhdGVkTWV0cmljcy5saXN0JG1tY0FsbGdlbmVBbGxkY3IgICMgbVJOQSBjb3VudCBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24KY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRybW1jQWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUodChhcHBseShjYWxjdWxhdGVkTWV0cmljcy5saXN0JG1tY0FsbGdlbmVBbGxkY3IsIDEsIGZ1bmN0aW9uKHgpe3hbMTpucm93KGRjLnIuZGYpXS94WzFdfSkpKQpjYWxjdWxhdGVkTWV0cmljcy5saXN0JHJtbWRyQWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUoZG8uY2FsbChyYmluZCwgbGFwcGx5KDE6NDgzOSwgZnVuY3Rpb24oZ2VuZUlEKXtjYWxjdWxhdGVkTWV0cmljcy5saXN0JG1tZHJBbGxnZW5lQWxsZGNyW2dlbmVJRCwgXS9zaW1JbnB1dEZlYXR1cmVzJG1STkFEZWNSYXRlTmV5bW90aW5fc2VjW2dlbmVJRF19KSkpICAjIGZvciBYMSB0aGlzIHdpbGwgYmUgMCwgIGZvciB0aGUgfjMwIGdlbmVzIHdob3NlIEdyZXNoYW1EZWNSYXRlID0gMCB0aGlzIHdpbGwgYmUgTmFOIGIvYyAwLzAgPSBOYU4KY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRybXR0QWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUodChhcHBseShjYWxjdWxhdGVkTWV0cmljcy5saXN0JG10dEFsbGdlbmVBbGxkY3IsIDEsIGZ1bmN0aW9uKHgpe3hbMTpucm93KGRjLnIuZGYpXS94WzFdfSkpKQpjYWxjdWxhdGVkTWV0cmljcy5saXN0JHJtdnR0QWxsZ2VuZUFsbGRjciA8LSBhc190aWJibGUodChhcHBseShjYWxjdWxhdGVkTWV0cmljcy5saXN0JG12dHRBbGxnZW5lQWxsZGNyLCAxLCBmdW5jdGlvbih4KXt4WzE6bnJvdyhkYy5yLmRmKV0veFsxXX0pKSkKY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRtaGxBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZShsb2coMikvY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRtbWRyQWxsZ2VuZUFsbGRjcikgIyBtZWFuIGhhbGYgbGlmZQpjYWxjdWxhdGVkTWV0cmljcy5saXN0JG1tZHBBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZShjYWxjdWxhdGVkTWV0cmljcy5saXN0JG1tbWRBbGxnZW5lQWxsZGNyL2NhbGN1bGF0ZWRNZXRyaWNzLmxpc3QkbW1jQWxsZ2VuZUFsbGRjcikKY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRtcmRBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZShjYWxjdWxhdGVkTWV0cmljcy5saXN0JG1tYnJBbGxnZW5lQWxsZGNyL3NpbUlucHV0RmVhdHVyZXMkZ2VuZUxlbmd0aF9jb2RvbikgI3JpYm9zb21lIGRlbnNpdHk9bnVtYmVyIG9mIHJpYm9zb21lcyBOIGRpdmlkZWQgYnkgdGhlIENEUyBsZW5ndGggTApjYWxjdWxhdGVkTWV0cmljcy5saXN0JHJtcmRBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZSh0KGFwcGx5KGNhbGN1bGF0ZWRNZXRyaWNzLmxpc3QkbXJkQWxsZ2VuZUFsbGRjciwgMSwgZnVuY3Rpb24oeCl7eFsxOm5yb3coZGMuci5kZildL3hbMV19KSkpICN4WzFdIGlzIGZvciBtUk5BY29uc3RhbnQKY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRybXRickFsbGdlbmVBbGxkY3IgPC0gYXNfdGliYmxlKHQoYXBwbHkoY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRtdGJyQWxsZ2VuZUFsbGRjciwgMSwgZnVuY3Rpb24oeCl7eFsxOm5yb3coZGMuci5kZildL3hbMV19KSkpICN4WzFdIGlzIGZvciBtUk5BY29uc3RhbnQKY2FsY3VsYXRlZE1ldHJpY3MubGlzdCRybXZ0YnJBbGxnZW5lQWxsZGNyIDwtIGFzX3RpYmJsZSh0KGFwcGx5KGNhbGN1bGF0ZWRNZXRyaWNzLmxpc3QkbXZ0YnJBbGxnZW5lQWxsZGNyLCAxLCBmdW5jdGlvbih4KXt4WzE6bnJvdyhkYy5yLmRmKV0veFsxXX0pKSkgI3hbMV0gaXMgZm9yIG1STkFjb25zdGFudAoKIyBjb252ZXJ0IGFsbCB0aGUgY2FsY3VsYXRlZE1ldHJpY3MubGlzdCBkYXRhZnJhbWVzIHRvIGxvbmcgZm9ybWF0CmNhbGN1bGF0ZWRNZXRyaWNzTG9uZy5saXN0IDwtIGxhcHBseSgxOmxlbmd0aChjYWxjdWxhdGVkTWV0cmljcy5saXN0KSwgZGYuY29udmVydC5mdW4pCgptY3BzckFsbGRjciA8LSByZWFkX2ZlYXRoZXIoIi4uL2NhbGN1bGF0ZWRNZXRyaWNzL21jcHNyQWxsZGNyLmZlYXRoZXIiKQoKIyBKb2luIGFsbCB0aGUgZGF0YWZyYW1lcyBpbiBjYWxjdWxhdGVkTWV0cmljcy5saXN0CmFsbFNpbUlucHV0T3V0cHV0IDwtIAogICAgY2FsY3VsYXRlZE1ldHJpY3NMb25nLmxpc3QgJT4lCiAgICAgICAgcHVycnI6OnJlZHVjZShsZWZ0X2pvaW4sIGJ5ID0gYygicGFyYUlEIiA9ICJwYXJhSUQiLCAiT1JGIiA9ICJPUkYiKSkgJT4lCiAgICAgICAgbGVmdF9qb2luKC4sIG1jcHNyQWxsZGNyLCAicGFyYUlEIikgJT4lCiAgICAgICAgbGVmdF9qb2luKC4sIHJtZnJfZGYsIGJ5ID0gInBhcmFJRCIpICU+JQogICAgICAgIGxlZnRfam9pbiguLCBkYy5yLmRmLCAicGFyYUlEIikgJT4lCiAgICAgICAgbGVmdF9qb2luKC4sIHNpbUlucHV0RmVhdHVyZXMsIGJ5ID0gIk9SRiIpCgp3cml0ZV9mZWF0aGVyKGFsbFNpbUlucHV0T3V0cHV0LCBwYXRoID0gIi4uL2FsbFNpbUlucHV0T3V0cHV0LmZlYXRoZXIiKQoKYGBgCgoKYGBge3J9CgphbGxTaW1JbnB1dE91dHB1dCAlPiUKICAgIGZpbHRlcihPUkYgPT0gIllCUjIwOEMiKQoKYWxsU2ltSW5wdXRPdXRwdXQgJT4lCiAgICBmaWx0ZXIoT1JGID09ICJZSlIxMDlDIikKCmFsbFNpbUlucHV0T3V0cHV0ICU+JQogICAgZmlsdGVyKE9SRiA9PSAiWUFMMDAxQyIpCgphbGxTaW1JbnB1dE91dHB1dCAlPiUKICAgIGZpbHRlcihPUkYgPT0gIllBTDAzNFctQSIpCmBgYA==